I have a Timestamp value that comes from my application. The user can be in any given local TimeZone.
Since this date is used for a WebService that assumes the time given is always in GMT, I have a need to convert the user's parameter from say (EST) to (GMT). Here's the kicker: The user is oblivious to his TZ. He enters the creation date that he wants to send to the WS, so what I need is:
User enters: 5/1/2008 6:12 PM (EST)
The parameter to the WS needs to be: 5/1/2008 6:12 PM (GMT)
I know TimeStamps are always supposed to be in GMT by default, but when sending the parameter, even though I created my Calendar from the TS (which is supposed to be in GMT), the hours are always off unless the user is in GMT. What am I missing?
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
...
private static java.util.Calendar convertTimestampToJavaCalendar(Timestamp ts_) {
java.util.Calendar cal = java.util.Calendar.getInstance(
GMT_TIMEZONE, EN_US_LOCALE);
cal.setTimeInMillis(ts_.getTime());
return cal;
}
With the previous Code, this is what I get as a result (Short Format for easy reading):
[May 1, 2008 11:12 PM]
You can solve it with Joda Time:
Java 8:
It looks like your TimeStamp is being set to the timezone of the originating system.
This is deprecated, but it should work:
The non-deprecated way is to use
but that would need to be done on the client side, since that system knows what timezone it is in.
java.time
The modern approach uses the java.time classes that supplanted the troublesome legacy date-time classes bundled with the earliest versions of Java.
The
java.sql.Timestamp
class is one of those legacy classes. No longer needed. Instead useInstant
or other java.time classes directly with your database using JDBC 4.2 and later.The
Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).If you must interoperate with an existing
Timestamp
, convert immediately into java.time via the new conversion methods added to the old classes.To adjust into another time zone, specify the time zone as a
ZoneId
object. Specify a proper time zone name in the format ofcontinent/region
, such asAmerica/Montreal
,Africa/Casablanca
, orPacific/Auckland
. Never use the 3-4 letter pseudo-zones such asEST
orIST
as they are not true time zones, not standardized, and not even unique(!).Apply to the
Instant
to produce aZonedDateTime
object.To generate a string for display to the user, search Stack Overflow for
DateTimeFormatter
to find many discussions and examples.Your Question is really about going the other direction, from user data-entry to the date-time objects. Generally best to break your data-entry into two parts, a date and a time-of-day.
Your Question is not clear. Do you want to interpret the date and the time entered by the user to be in UTC? Or in another time zone?
If you meant UTC, create a
OffsetDateTime
with an offset using the constant for UTC,ZoneOffset.UTC
.If you meant another time zone, combine along with a time zone object, a
ZoneId
. But which time zone? You might detect a default time zone. Or, if critical, you must confirm with the user to be certain of their intention.To get a simpler object that is always in UTC by definition, extract an
Instant
.…or…
Send to your database.
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.Date and Timestamp objects are timezone-oblivious: they represent a certain number of seconds since the epoch, without committing to a particular interpretation of that instant as hours and days. Timezones enter the picture only in GregorianCalendar (not directly needed for this task) and SimpleDateFormat, which need a timezone offset to convert between separate fields and Date (or long) values.
The OP's problem is right at the beginning of his processing: the user inputs hours, which are ambiguous, and they are interpreted in the local, non-GMT timezone; at this point the value is "6:12 EST", which can be easily printed as "11.12 GMT" or any other timezone but is never going to change to "6.12 GMT".
There is no way to make the SimpleDateFormat that parses "06:12" as "HH:MM" (defaulting to the local time zone) default to UTC instead; SimpleDateFormat is a bit too smart for its own good.
However, you can convince any SimpleDateFormat instance to use the right time zone if you put it explicitly in the input: just append a fixed string to the received (and adequately validated) "06:12" to parse "06:12 GMT" as "HH:MM z".
There is no need of explicit setting of GregorianCalendar fields or of retrieving and using timezone and daylight saving time offsets.
The real problem is segregating inputs that default to the local timezone, inputs that default to UTC, and inputs that really require an explicit timezone indication.
Method for converting from one timeZone to other(probably it works :) ).
You say that the date is used in connection with web services, so I assume that is serialized into a string at some point.
If this is the case, you should take a look at the setTimeZone method of the DateFormat class. This dictates which time zone that will be used when printing the time stamp.
A simple example: