9

I have a database field that contains a raw date field (stored as character data), such as

Friday, September 26, 2008 8:30 PM Eastern Daylight Time

I can parse this as a Date easily, with SimpleDateFormat

DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
Date scheduledDate = dbFormatter.parse(rawDate);

What I'd like to do is extract a TimeZone object from this string. The default TimeZone in the JVM that this application runs in is GMT, so I can't use .getTimezoneOffset() from the Date parsed above (because it will return the default TimeZone).

Besides tokenizing the raw string and finding the start position of the Timezone string (since I know the format will always be EEEE, MMMM dd, yyyy hh:mm aa zzzz) is there a way using the DateFormat/SimpleDateFormat/Date/Calendar API to extract a TimeZone object - which will have the same TimeZone as the String I've parsed apart with DateFormat.parse()?

One thing that bugs me about Date vs Calendar in the Java API is that Calendar is supposed to replace Date in all places... but then they decided, oh hey let's still use Date's in the DateFormat classes.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • did u got solution for this issue? – pranjaljain Sep 24 '15 at 10:54
  • Regarding last paragraph, the `Date` & `Calendar` classes are a bloody mess: poorly-designed, confusing, and troublesome. Avoid them. Use the [java.time](http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) classes instead. – Basil Bourque Oct 26 '16 at 05:09

7 Answers7

2

I found that the following:

        DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
        dbFormatter.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
        Date scheduledDate = dbFormatter.parse("Friday, September 26, 2008 8:30 PM Eastern Daylight Time");
        System.out.println(scheduledDate);
        System.out.println(dbFormatter.format(scheduledDate));
        TimeZone tz = dbFormatter.getTimeZone();
        System.out.println(tz.getDisplayName());
        dbFormatter.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
        System.out.println(dbFormatter.format(scheduledDate));

Produces the following:

Fri Sep 26 20:30:00 CDT 2008
Friday, September 26, 2008 08:30 PM Eastern Standard Time
Eastern Standard Time
Friday, September 26, 2008 08:30 PM Central Daylight Time

I actually found this to be somewhat surprising. But, I guess that shows that the answer to your question is to simply call getTimeZone on the formatter after you've parsed.

Edit: The above was run with Sun's JDK 1.6.

Ed Thomas
  • 1,153
  • 1
  • 12
  • 21
1

tl;dr

ZonedDateTime.parse( 
    "Friday, September 26, 2008 8:30 PM Eastern Daylight Time" , 
    DateTimeFormatter.ofPattern( "EEEE, MMMM d, uuuu h:m a zzzz" ) 
).getZone()

java.time

The modern way is with the java.time classes. The Question and other Answers use the troublesome old legacy date-time classes or the the Joda-Time project, both of which are now supplanted by the java.time classes.

Define a DateTimeFormatter object with a formatting pattern to match your data.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEEE, MMMM d, uuuu h:m a zzzz" );

Assign a Locale to specify the human language of the name-of-day and name of month, as well as the cultural norms for other formatting issues.

f = f.withLocale( Locale.US );

Lastly, do the parsing to get a ZonedDateTime object.

String input = "Friday, September 26, 2008 8:30 PM Eastern Daylight Time" ;
ZonedDateTime zdt = ZonedDateTime.parse( input , f );

zdt.toString(): 2008-09-26T20:30-04:00[America/New_York]

You can ask for the time zone from the ZonedDateTime, represented as a ZoneId object. You can then interrogate the ZoneId if you need more info about the time zone.

ZoneId z = zdt.getZone();

See for yourself in IdeOne.com.

ISO 8601

Avoid exchanging date-time data in this kind of terrible format. Do not assume English, do not accessorize your output with things like the name-of-day, and never use pseudo-time-zones such as Eastern Daylight Time.

For time zones: 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(!).

For serializing date-time values to text, use only the ISO 8601 formats. The java.time classes use these formats by default when parsing/generating strings to represent their value.


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 java.time.

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?

  • Java SE 8 and SE 9 and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

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.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

@Ed Thomas:

I've tried something very similar to your example and I get very different results:

String testString = "Friday, September 26, 2008 8:30 PM Pacific Standard Time";
DateFormat df = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");

System.out.println("The default TimeZone is: " + TimeZone.getDefault().getDisplayName());

System.out.println("DateFormat timezone before parse: " + df.getTimeZone().getDisplayName());

Date date = df.parse(testString);

System.out.println("Parsed [" + testString + "] to Date: " + date);

System.out.println("DateFormat timezone after parse: " + df.getTimeZone().getDisplayName());

Output:

The default TimeZone is: Eastern Standard Time

DateFormat timezone before parse: Eastern Standard Time

Parsed [Friday, September 26, 2008 8:30 PM Pacific Standard Time] to Date: Sat Sep 27 00:30:00 EDT 2008

DateFormat timezone after parse: Eastern Standard Time

Seems like DateFormat.getTimeZone() returns the same TimeZone before and after the parse()... even if I throw in an explicit setTimeZone() before calling parse().

Looking at the source for DateFormat and SimpleDateFormat, seems like getTimeZone() just returns the TimeZone of the underlying Calendar... which will default to the Calendar of the default Locale/TimeZone unless you specify a certain one to use.

Community
  • 1
  • 1
matt b
  • 138,234
  • 66
  • 282
  • 345
  • java version "1.4.2_14" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_14-b05) Java HotSpot(TM) Client VM (build 1.4.2_14-b05, mixed mode) – matt b Sep 19 '08 at 13:25
1

I recommend checking out the Joda Time date and time API. I have recently been converted to a believer in it as it tends to be highly superior to the built-in support for dates and times in Java. In particular, you should check out the DateTimeZone class. Hope this helps.

http://joda-time.sourceforge.net/

http://joda-time.sourceforge.net/api-release/index.html

Aaron
  • 23,450
  • 10
  • 49
  • 48
  • The *Joda-Time* project is now in maintenance mode. Its principal author, Stephen Colebourne, went on to lead JSR 310 and its implementation, the *java.time* classes in OpenJDK, the successor to Joda-Time. – Basil Bourque Nov 23 '18 at 16:43
0

Well as a partial solution you could use a RegEx match to get the timezone since you will always have the same text before it. AM or PM.

I don't know enough about Java timezones to get you the last part of it.

Mitchel Sellers
  • 62,228
  • 14
  • 110
  • 173
0

The main difference between Date and Calendar is, that Date is just a value object with no methods to modify it. So it is designed for storing a date/time information somewhere. If you use a Calendar object, you could modify it after it is set to a persistent entity that performs some business logic with the date/time information. This is very dangerous, because the entity has no way to recognize this change. The Calendar class is designed for operations on date/time, like adding days or something like that.

Playing around with your example I get the following:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class TimeZoneExtracter {

    public static final void main(String[] args) throws ParseException {
        DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
        System.out.println(dbFormatter.getTimeZone());
        dbFormatter.parse("Fr, September 26, 2008 8:30 PM Eastern Daylight Time");
        System.out.println(dbFormatter.getTimeZone());
    }

}

Output:

sun.util.calendar.ZoneInfo[id="Europe/Berlin"... sun.util.calendar.ZoneInfo[id="Africa/Addis_Ababa"...

Is this the result you wanted?

Roland Schneider
  • 3,615
  • 3
  • 32
  • 43
0

Ed has it right. you want the timeZone on the DateFormat object after the time has been parsed.

 String rawDate = "Friday, September 26, 2008 8:30 PM Eastern Daylight Time";
 DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
 Date scheduledDate = dbFormatter.parse(rawDate);

 System.out.println(rawDate); 
 System.out.println(scheduledDate); 
 System.out.println(dbFormatter.getTimeZone().getDisplayName());

produces

Friday, September 26, 2008 8:30 PM Eastern Daylight Time
Fri Sep 26 20:30:00 CDT 2008
Eastern Standard Time
Mike Pone
  • 18,705
  • 13
  • 53
  • 68
  • 2
    You might want to test with something other than "Eastern Daylight Time" in the date String - dbFormatter.getTimeZone() is just returning the default (your) timezone. – matt b Sep 17 '08 at 19:08