How would you represent date of birth in your java model?
The other answers use outmoded classes.
java.time
Both Joda-Time and the old java.util.Date/.Calendar classes have been supplanted by the java.time framework built into Java 8 and later. Defined by JSR 310. Extended by the ThreeTen-Extra project. Back-ported to Java 6 & 7 by the ThreeTen-BackPort project, which is wrapped for Android by the ThreeTenABP project.
LocalDate
A date-only value without time-of-day and without time zone can be represented by the LocalDate
class. Such a class was lacking in the old date-time classes bundled with the earliest versions of Java. The old java.sql.Date
class pretends to be date-only but in fact has a time-of-day inherited from java.util.Date
(a date-time value).
LocalDate dateOfBirth = LocalDate.of( 1979 , 1 , 10 );
Without a time of day nor time zone, a date of birth is inherently inaccurate for determining one’s age. But in nearly all use-cases we don't care; give-or-take part of a day is close enough.
ZonedDateTime
For a meeting we cannot be so loosey-goosey. We need a date, a time, and a time zone. In java.time that means ZonedDateTime
class. The time zone is the key element missing from the scenario in the Question. Add the time zone and all is well.
ZoneId zoneIdMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( 2010 , 1 , 10 , 20 , 0 , 0 , zoneIdMontreal );
Now communicate the objects to another machine. Both remain intact, the same date-only value for date-of-birth (1979-01-10) and the same Montréal date-time for the meeting.
Adjust time zone
You might then want to adjust that meeting to another time zone expected by the person using this other machine.
ZoneId zoneIdParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = zdtMontreal.withZone( zoneIdParis );
We have the same moment on the timeline represented in two fashions, in two objects, zdtMontreal & zdtParis.
LocalDateTime
If your nextMeeting
has no time zone nor offset-from-UTC info, then represent as a LocalDateTime
object. In the database it would be stored as a type like TIMESTAMP WITHOUT TIME ZONE
.
Such values do not represent a moment in the timeline. They represent only a range of possible moments. To determine an actual moment you must provide the context of a specific time zone.
For storing future date-time values such as a planned meeting further out than a few weeks, doing so without time zone may be appropriate. Politicians around the world have shown a proclivity for often changing Daylight Saving Time and otherwise redefining their time zones. And they often do so with little warning, as little as only several weeks warning.
To determine an actual moment such as showing a schedule in a calendar, apply a time zone ZoneId
to get a ZonedDateTime
.
ISO 8601
The java.time classes use the standard ISO 8601 formats by default when parsing/generating textual representations of date-time values. The ZonedDateTime
class goes one step further by extending ISO 8601 to append the name of the time zone in square brackets.
If serializing values via text, use to the sensible and unambiguous formats of ISO 8601.
None of the issues raised in the Question remain. Using an excellent date-time library and ISO 8601 such as java.time solves the problem.
Database
Your database should use date-only type for the birthdate, and a timestamp-with-time-zone type for the meeting (see SQL data types in Wikipedia and in your database’s documentation). Your JDBC driver mediates both types for you.
Eventually JDBC drivers will be updated to directly use java.time types. But until then we must convert to java.sql types such as java.sql.Date
and java.sql.Timestamp
. New methods have been added to the old classes to support these conversions.
java.sql.Date sqlDateOfBirth = java.sql.Date.valueOf( dateOfBirth );
java.sql.Timestamp sqlMeeting = java.sql.Timestamp.valueOf( zdtMontreal );
Then call setDate
and setTimestamp
on your PreparedStatement
.
Going the other direction, from database to Java, call getDate
and getTimestamp
on your ResultSet
. Then translate immediately to java.time types, avoiding the use of the java.sql types in your business logic.
For the date-time value, we must go through an Instant
object. The Instant
is a moment on the timeline in UTC. We apply a time zone to get a wall-clock time for the user.
LocalDate dateOfBirth = mySqlDate.toLocalDate();
Instant instant = mySqlTimestamp.toInstant();
ZonedDateTime zdtMontreal = ZonedDateTime.ofInstant( instant , zoneIdMontreal );
Use LocalDate from JodaTime and only store the date for the birthday, not the time.