1

I have a Date Object which I need to convert to the logged in user's timezone. The problem is that the timezone is represented in our DB simply as a String value of GMT plus or minus the offset in hours. So for example "GMT" or "GMT-5" for New york time or "GMT+5".

How can I convert my Date Object to the User's time when all I have are String like "GMT-3" or "GMT+5"?

Thanks in advance for any help.

Ashot Karakhanyan
  • 2,804
  • 3
  • 23
  • 28
AbuMariam
  • 3,282
  • 13
  • 49
  • 82
  • 3
    Are you able to change your database structure? If you're just storing an offset, it would be sensible to store that as a number instead - and bear in mind that not all offsets will be whole numbers of hours. Also note that an offset isn't the same as a time zone. There can be multiple time zones which currently have the same offset, but will have different offsets at other times. – Jon Skeet Feb 08 '14 at 16:58
  • 2
    Also, the Date object shouldn't have to be "converted". A Date object is timezone agnostic. You should only care about the time zone when formatting a Date to a String, or parsing a String to a Date. – JB Nizet Feb 08 '14 at 17:07

2 Answers2

2

An example should help, but it seems a 1 character ISO 8601 time zone:

String myDate="2001-07-04T12:08:56GMT-3";

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'GMT'X");

if (myDate.indexOf("GMT-") >= myDate.length() -1 -4) {
    myDate = myDate.replace("-","-0");
}
if (myDate.indexOf("GMT+") >= myDate.length() -1 -4) {
    myDate = myDate.replace("+","+0");
}

System.out.println(format.parse(myDate));

it should work.

  • the yyyy-MM-dd'T'HH:mm:ss'GMT'X is compliant with iso8601 time zone
  • myDate = myDate.replace("-","-0"); adjusts the date to your format
venergiac
  • 7,469
  • 2
  • 48
  • 70
  • Good example. But please keep in mind that SimpleDateFormat is NOT ThreadSafe. When using DB connections you often have a pool of threads and can run into "strange behaviour" because of the missing thread safety. I would recommend FastDateFormat, which works exactly like SimpleDateFormat but has built in thread safety: http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/FastDateFormat.html – elToro Feb 08 '14 at 21:40
  • Yes SimpledateFormat is not thread safe since a synchonization could cause loss of performance and making a new instance is faster then synchonization. FastDateFormat should be a good opportunity, but it doesn't support iso8601 .... – venergiac Feb 09 '14 at 08:32
1

Offset ≠ Time Zone

As Jon Skeet said in comment, a time zone is more than just an offset from UTC/GMT. Storing the offset hours (and minutes) is a less-than-optimal strategy for handling date-time in your database/storage.

Joda-Time

The java.util.Date & java.util.Calendar classes are notoriously troublesome. Avoid them. Use Joda-Time. Or, in Java 8, use the new java.time.* package, defined by JSR 310, and inspired by Joda-Time but re-architected.

We can create a DateTimeZone to represent the offset, but as noted this does not make a complete time zone logically.

We can pass a java.util.Date object directly to a Joda-Time DateTime constructor. Along with that we pass a DateTimeZone object. To go the other direction of conversion, call toDate on a DateTime object.

java.util.Date date = new java.util.Date(); // Retrieved from elsewhere. Faked here.

String offsetInput = "GMT-5";
int offsetHours = 0, offsetMinutes = 0;
offsetInput = offsetInput.replace( "GMT", "" ); // Delete 'GMT' characters.
String[] parts = offsetInput.split(":"); // About splitting a string: http://stackoverflow.com/q/3481828/642706

// Handle results of split.

if( parts.length == 0 ) {
    // Add some error handling here
} 

if ( parts.length >= 1 ) {
    offsetHours = Integer.parseInt( parts[0] ); // Retrieve text of first number (zero-based index counting).
}

if ( parts.length >= 2 ) {
    offsetMinutes = Integer.parseInt( parts[1] ); // Retrieve text of second number (zero-based index counting).
}

if( parts.length >= 3 ) {
    // Add some error handling here
} 

DateTimeZone partialTimeZoneWithOnlyOffset = DateTimeZone.forOffsetHoursMinutes( offsetHours, offsetMinutes );

DateTime dateTime = new DateTime( date, partialTimeZoneWithOnlyOffset );

Dump to console…

System.out.println( "date: " + date ); // BEWARE: JVM's default time zone applied in the implicit call to "toString" of a Date. Very misleading.
System.out.println( "partialTimeZoneWithOnlyOffset: " + partialTimeZoneWithOnlyOffset );
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTime with alternate formatting: " + DateTimeFormat.forStyle( "FF" ).withLocale( Locale.US ).print(  dateTime ) );

When run…

date: Sat Feb 08 22:40:57 PST 2014
partialTimeZoneWithOnlyOffset: -05:00
dateTime: 2014-02-09T01:40:57.810-05:00
dateTime with alternate formatting: Sunday, February 9, 2014 1:40:57 AM -05:00
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154