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.
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:
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.
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
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 ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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.
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.
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?
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
Related
How can I get Date.toString() to produce an output that SimpleDateFormat can parse correctly for Dates around 1 Jan 1970 (I assume this applies to winter of 1968 and 1969 as well)
If I run the following,
System.out.println(TimeZone.getDefault());
Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
Date date2 = sdf.parse(date.toString());
System.out.println("date: " + date);
System.out.println("date2: " + date2);
Date date3 = sdf.parse(date2.toString());
System.out.println("date3: " + date3);
This prints
sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=3600000,useDaylight=true,transitions=242,lastRule=java.util.SimpleTimeZone[id=Europe/London,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
date: Thu Jan 01 01:00:00 GMT 1970
date2: Thu Jan 01 02:00:00 GMT 1970
date3: Thu Jan 01 03:00:00 GMT 1970
The problem is that London was in BST on 1 Jan 1970. So the correct date should be either
date: Thu Jan 01 01:00:00 BST 1970
or
date: Thu Jan 01 00:00:00 GMT 1970
but it seems a confusion of the two.
And while I would love to not support java.util.Date, it's not an option for me.
tl;dr
Your input is invalid as BST (British Summer Time) was not in effect during the winter.
BST cannot be reliably parsed, as it is a non-standard non-unique pseudo-zone.
There is no need to mess around with SimpleDateFormat. Let the modern java.time classes do the heavy lifting.
And while I would love to not support java.util.Date, it's not an option for me.
At the edges of your code, convert to-from the legacy and modern classes.
// Convert from legacy to modern.
Instant instant = myJavaUtilDate.toInstant() ;
// Convert from modern to legacy.
java.util.Date myJavaUtilDate = Date.from( instant ) ;
No BST in winter
Apparently the “B” in your BST is meant to be British. But BST in that context means British Summer Time. This means Daylight Saving Time (DST) which is engaged in the summer time, not the winter. So your input string of a January date combined with BST is nonsensical.
Double-Summertime
There is a further complication to your example of a moment in 1970 with a British time zone.
The practice of DST in Britain using an offset of one hour ahead of UTC (+01:00) in summer, and an offset of zero (+00:00) in the winter for Standard Time is current practice. That has not always been the case.
Back in 1970, Britain was trialling a “double-summertime”. In that experiment of 1968-1971, winter time was one hour ahead of UTC rather than zero, and summer time was two hours ahead of UTC instead of the one hour used nowadays. This put British time more in common with continental Europe and was hoped to reduce accidents.
So if we adjust a moment in January of 1970, we expect to jump to one hour ahead for time zone Europe/London. Whereas a moment in January of 2019, we expect no jump, the time-of-day in Britain will be the same as UTC (an offset-from-UTC of zero hours-minutes-seconds).
Avoid pseudo-zones
Avoid these 2-4 character pseudo-zones such as BST. They are not standardized. They are not even unique! So BST can be interpreted to be the time zone Pacific/Bougainville just as well as British Summer 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 2-4 letter abbreviation such as BST or EST or IST as they are not true time zones, not standardized, and not even unique(!).
Convert
You can convert between the legacy and modern date-time classes easily. New conversion methods have been added to the old classes. Look for from, to, and valueOf methods, per the naming conventions.
java.util.Date ⇄ java.time.Instant
java.util.GregorianCalendar ⇄ java.time.ZonedDateTime
java.sql.Date ⇄ java.time.LocalDate
java.sql.Timestamp ⇄ java.time.Instant
Converting
Your input string of 00:00 on January 1, 1970 happens to be the epoch reference date used by both the legacy and modern date-time classes. We have a constant for that value.
Instant epoch = Instant.EPOCH ;
instant.toString(): 1970-01-01T00:00:00Z
See that same moment through your time zone of Europe/London.
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = epoch.atZone( z ) ;
zdt.toString(): 1970-01-01T01:00+01:00[Europe/London]
Notice that above-mentioned Double-Summertime experiment in effect then. If we try the same code for 2019, we get an offset-from-UTC of zero.
ZonedDateTime zdt2019 =
Instant
.parse( "2019-01-01T00:00Z" )
.atZone( ZoneId.of( "Europe/London" ) )
;
zdt2019.toString(): 2019-01-01T00:00Z[Europe/London]
To convert to a java.util.Date, we need an java.time.Instant object. An Instant represents a moment in UTC. We can extract an Instant from our ZonedDateTime object, effectively adjusting from a zone to UTC. Same moment, different wall-clock time.
Instant instant = zdt.toInstant():
We should now be back where we started, at the epoch reference date of 1970-01-01T00:00:00Z.
instant.toString(): 1970-01-01T00:00:00Z
To get the java.util.Date object you may need to interoperate with old code not yet updated to java.time classes, use the new Date.from method added to the old class.
java.util.Date d = Date.from( instant ) ; // Same moment, but with possible data-loss as nanoseconds are truncated to milliseconds.
d.toString(): Thu Jan 01 00:00:00 GMT 1970
By the way, be aware of possible data-loss when converting from Instant to Date. The modern classes have a resolution of nanoseconds while the legacy classes use milliseconds. So part of your fractional second may be truncated.
See all the code above run live at IdeOne.com.
To convert the other direction, use the Date::toInstant method.
Instant instant = d.toInstant() ;
ISO 8601
Avoid using text in custom formats for exchanging date-time values. When serializing date-time values as human-readable text, use only the standard ISO 8601 formats. The java.time classes use these formats by default.
Those strings you were experimenting with parsing are a terrible format and should never be used for data-exchange.
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
I may cite https://bugs.openjdk.java.net/browse/JDK-6609362?jql=text%20~%20%22epoch%20gmt%22:
Please use Z to format and parse historical time zone offset changes
to avoid confusions with historical time zone name changes.
public class Test {
public static void main(String[] args) throws ParseException {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
SimpleDateFormat f = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
Date d = new Date(0);
for (int i = 0; i < 10; i++) {
String s = f.format(d);
System.out.println(s);
d = f.parse(s);
}
} } ```
This is why I hate the Date Library.
As implied, BST should be used during the summer, and the calendar defines it as such.
sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=3600000,useDaylight=true,transitions=242,lastRule=java.util.SimpleTimeZone[id=Europe/London,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
Except, for, TIL of The adventures of year-round British Summer Time!
A further inquiry during 1966–67 led the government of Harold Wilson to introduce the British Standard Time experiment, with Britain remaining on GMT+1 throughout the year. This took place between 27 October 1968 and 31 October 1971, when there was a reversion to the previous arrangement.
If you test dates around this period you will find the dates drifting off by an hour each parse, up to the switchover points.
The time code for Europe/London is GMT, with daylight savings using BST.
The toString method of Date "normalizes" the output by removing daylight savings time to pick what time zone to print. The options are GMT and BST. The Europe/London time of 01:00:00 printed as 01:00:00 GMT even though it is operating on GMT+1 time. So in other words, date.toString()does not work properly for this swath of time around the epoch because it uses GMT as a time zone for a time zone that is ostensibly not GMT/CET. The time itself is correct, but not the time zone.
The "simplest" solution I can come up with is relatively nasty from a sanity checkpoint, but can probably be made more elegant.
private static final Date experimentEnd = new Date(1971-1900, 11-1, 11);
private static final Date experimentStart = (new Date(1968-1900, 10-1, 26));
private static boolean bstExperimentTime(Date date) {
return date.after(experimentStart) && date.before(experimentEnd);
}
public static String forDateParsing(Date date) {
if(bstExperimentTime(date))
return date.toString().replace("GMT", "CET");
return date.toString();
}
public static String forDatePrinting(Date date) {
if(bstExperimentTime(date))
return date.toString().replace("GMT", "BST");
return date.toString();
}
Any date you need to parse with default "Europe/London" time zone needs to be passed through the parse formatter to convert GMT -> CET, which is the correct GMT+1.
Any date you need to print with default "Europe/London" time zone needs to be passed through the parse formatter to convert GMT -> BST, which is the correct display.
I am working on server and server is sending me date on GMT Local Date like Fri Jun 22 09:29:29 NPT 2018 on String format and I convert it into Date like below:
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy",Locale.English);
Date newDate=simpleDateFormat.parse("Fri Jun 22 09:29:29 NPT 2018");
TimeAgo ta=new TimeAgo();
Log.d(TAG,""+ta.timeAgo(newDate));
What I need is take out the Time in Ago like 5 hours ago for that I use the one github project on which returns TimeAgo on passing date.
I have already look at this answer but didn't solve my problem.
Exception: Err java.text.ParseException: Unparseable date: "Fri Jun 22 09:29:29 NPT 2018" (at offset 20)
Err java.text.ParseException: Unparseable date: "Fri Jun 22 09:29:29 NPT 2018" (at offset 20)
NPT is not recognized as a time zone abbreviation
The parsing of your date-time string (apparently the output from Date.toString()) is the problem (not the subsequent use of TimeAgo, which you could have left out from the question to make it clearer). The unparseable part is at index 20, that is where it says NPT, which I take to mean Nepal Time. So SimpleDateFormat on your Android device or emulator doesn’t recognize NPT as a time zone abbreviation.
Time zone abbreviations come as part of the locale data. I am not an Android developer and don’t know from where Android gets its locale data. A fast web search mentioned ICU and CLDR. You can search more thoroughly and no doubt find information I didn’t find.
I am presenting three suggestions for you to try. I admit at once that the first two are unlikely to solve your problem, but I nevertheless find them worth trying. And I promise that the third will work if the first two don’t.
1. Use ThreeTenABP and java.time
I agree with the answer by notyou that the classes Date and SimpleDateFormat are outmoded and that it’s better to use java.time, the modern Java date and time API. Can you do that on Android prior to Android O? Yes, most of java.time has been backported. The Android edition of the backport is called ThreeTenABP. Use the links at the bottom. Then try:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);
ZonedDateTime newDateTime
= ZonedDateTime.parse("Fri Jun 22 09:29:29 NPT 2018", formatter);
System.out.println(newDateTime);
Make sure you use the imports for the backport:
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
I have tested with the same backport, only not the Android edition. I got:
2018-06-22T09:29:29+05:45[Asia/Kathmandu]
I suspect that ThreeTenABP uses the same locale data, though, and if so, this doesn’t solve your problem.
2. Set the time zone on the formatter
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT)
.withZone(ZoneId.of("Asia/Kathmandu"));
If it works, I find it straightforward and clean. If you insist on using SimpleDateFormat, you can try a similar trick with it. I get the same output as above.
3. Handle NPT as literal text
This is a hack: require that the three letters NPT occur in the string without interpreting them as a time zone. This eliminates the need for the abbreviation to be recognized as a time zone, so will work.
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("EEE MMM dd HH:mm:ss 'NPT' yyyy", Locale.ROOT)
.withZone(ZoneId.of("Asia/Kathmandu"));
We also need to set the time zone since this is now the only place Java can get the time zone from.
But TimeAgo requires a Date
To obtain an old-fashioned Date object for TimeAgo, convert like this:
Date newDate = DateTimeUtils.toDate(newDateTime.toInstant());
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
The Date class is predominantly deprecated, so I would suggest not to use that.
Perhaps consider using something like the ZonedDateTime class for your problem.
If you're just looking for 5 hours before the String sent over to you, you could use something like:
String time = "Fri Jun 22 09:29:29 NPT 2018";
DateTimeFormatter format = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz uuuu");
ZonedDateTime zdt = ZonedDateTime.parse(time, format);
System.out.println(zdt.minusHours(5));
I am working with date strings that need to be converted to java.util.date objects.
I'm using the following code to do this:
public void setDates(String from, String to) throws ParseException
{
Date fromDate = new Date();
Date toDate = new Date();
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
fromDate = df.parse(from);
toDate = df.parse(to);
this.setDepartDate(fromDate);
this.setReturnDate(toDate);
}
The problem is that the string values that I have to convert are always(And I have no control over this) in the following format: "20 September, 2013".
This causes my function to through a ParseException when it reaches fromDate = df.parse(from);
Could anyone help me understand why, and perhaps suggest a solution?
Check out the SimpleDateFormat JavaDocs for the available format options, but basically, you need to change your date format to something more like dd MMMM, yyyy
try {
String dateValue = "20 September, 2013";
SimpleDateFormat df = new SimpleDateFormat("dd MMMM, yyyy");
Date date = df.parse(dateValue);
System.out.println(date);
} catch (ParseException exp) {
exp.printStackTrace();
}
Which outputs...
Fri Sep 20 00:00:00 EST 2013
As per the javadoc use following format
SimpleDateFormat df = new SimpleDateFormat("dd MMMMM, yyyy");
Also decide if this parsing needs to be Lenient or not and if it needs to be strict use setLenient(false)
By default, parsing is lenient: If the input is not in the form used
by this object's format method but can still be parsed as a date, then
the parse succeeds. Clients may insist on strict adherence to the
format by calling setLenient(false).
Also note that SimpleDateFormat is not threadsafe. If there is a choice I recommend using Joda Time Library that provide much enhanced functionality.
You wrote
[...] in the following format: "20 September, 2013".
Then your SimpleDateFormat should be
"dd MMM, yyyy"
You can check out the SimpleDateFormat documentation.
When you parse a date, you need to know some context or use some assumptions. You can use SimpleDateFormat, but you may need to pre-parse the string to see which format it is before you use it. You may have to try multiple format to see if one or more way to parse the date.
BTW is 01/02/30 the 1st Feb 1930 or 2nd Jan 2030 or 30th feb 2001, you need to know something about what the date is likely to mean or have some control over the format.
LocalDate
The modern approach uses the java.time classes that supplanted the troublesome old date-time classes (Date, Calendar, etc.) years ago.
String input = "20 September, 2013" ;
Locale locale = Locale.US ; // Determines the human language and cultural norms used in parsing the input string.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "d MMMM, uuuu" , locale ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
See this code run live at IdeOne.com.
ld.toString(): 2013-09-20
ZonedDateTime
If you want a time-of-day with that date, such as the first moment of the day, you must specify a time zone. A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your [desired/expected time zone][2] explicitly as an argument.
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/Montreal" ) ;
Apply that ZoneId to get a ZonedDateTime. Never assume the day starts at 00:00:00. Anomalies such as Daylight Saving Time (DST) mean the day may start at another time such as 01:00:00. Let java.time determine the first moment of the day.
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
Instant
To adjust into UTC, extract an Instant.
Instant instant = zdt.toInstant() ;
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
You need to use following date pattern, dd MMMM, yyyy
Try this code,
String dateValue = "20 September, 2013";
// Type of different Month views
SimpleDateFormat sdf = new SimpleDateFormat("dd MMMM, yyyy"); //20 September, 2013
SimpleDateFormat sdf1 = new SimpleDateFormat("dd MM, yyyy"); //20 09, 2013
SimpleDateFormat sdf2 = new SimpleDateFormat("dd MMM, yyyy"); //20 Sep, 2013
Date date = sdf.parse(dateValue); // returns date object
System.out.println(date); // outputs: Fri Sep 20 00:00:00 IST 2013
I understand that java Date is timezoneless and trying to set different timezone on Java Calendar wouldn't convert date to an appropriate Time Zone. So I have tried following code
public static String DATE_FORMAT="dd MMM yyyy hh:mm:ss";
public static String CURRENT_DATE_STRING ="31 October 2011 14:19:56 GMT";
DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(dateFormat.parseObject(CURRENT_DATE_STRING));
but it outputs wrong date Mon Oct 31 16:19:56 when it must be 12:19:56?
The main issue here is your date format string is using hh (12-hour clock) instead of HH (24-hour)
Secondly, your date format should specify that your date string contains the timezone.
(Alternatively you could uncomment the commented line, to tell it the correct timezone).
Thirdly, you should use a DateFormat to output the time to screen aswell...
Finally, UTC = GMT, so the UTC time is also 14:19:56
(GMT, 'British Winter Time', is the same as UTC, whereas BST is one hour ahead)
public class DateFormatTest {
public static String DATE_FORMAT="dd MMM yyyy HH:mm:ss z";
public static String CURRENT_DATE_STRING ="31 October 2011 14:19:56 GMT";
public static void main(String[] args) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
//dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
Date d= dateFormat.parse(CURRENT_DATE_STRING);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(dateFormat.format(d));
}
}
Output: 31 Oct 2011 14:19:56 UTC
HTH
tl;dr
On that date, at that time, in some eastern Europe time zones, the clocks were running two hours ahead of UTC. So the hour of 14 in UTC (GMT) will appear as 16 (not 12) in zones such as Europe/Helsinki.
ZonedDateTime
.parse
(
"31 October 2011 14:19:56 GMT" ,
DateTimeFormatter.ofPattern
(
"dd MMMM uuuu HH:mm:ss z" ,
Locale.US
)
)
.withZoneSameInstant
(
ZoneId.of( "Europe/Helsinki" )
)
.toString()
2011-10-31T16:19:56+02:00[Europe/Helsinki]
java.time
I understand that java Date is timezoneless
Actually, a java.util.Date represents a moment as seen in UTC, an offset of zero hours-minutes-seconds.
Beware of Date::toString. That terrible toString method dynamically applies the JVM’s current default time zone while generating its text. This creates an illusion of that time zone having been part of the object. One of many reasons to never use this class.
trying to set different timezone on Java Calendar wouldn't convert date to an appropriate Time Zone
You should be using the modern java.time classes, never Calendar. Specifically, use ZonedDateTime to represent a moment as seen through the wall-clock time used by the people of a particular region (a time zone).
"31 October 2011 14:19:56 GMT";
Your input of "31 October 2011 14:19:56 GMT" does not match your formatting pattern "dd MMM yyyy hh:mm:ss". That pattern fails to account for the offset of your input, an offset of zero hours-minutes-seconds indicated by the GMT at the end.
Firstly, do not exchange date-time values using such formats. Learn to use ISO 8601 standard formats for exchanging date-time values as text. The java.time classes conveniently use these standard formats by default when parsing/generating text, so no need to specify a pattern at all.
But if you must parse that particular input string of yours, define a formatting pattern to match.
String input = "31 October 2011 14:19:56 GMT";
Locale locale = Locale.US;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd MMMM uuuu HH:mm:ss z" , locale );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
Notice how we specified a Locale, to determine the human language and cultural norms used in translation of your input.
EEST – Eastern European Summer Time
Apparently you want to view this moment as seen in the time zone of eastern Europe. I will arbitrarily choose one of the several time zones in that area.
Be aware that EEST is not a real time zone. Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST or EEST as they are not true time zones, not standardized, and not even unique(!).
ZoneId zoneHelsinki = ZoneId.of( "Europe/Helsinki" );
ZonedDateTime zdtHelsinki = zdt.withZoneSameInstant( zoneHelsinki );
Dump to console.
System.out.println( "zdt = " + zdt );
System.out.println( "zdtHelsinki = " + zdtHelsinki );
zdt = 2011-10-31T14:19:56Z[GMT]
zdtHelsinki = 2011-10-31T16:19:56+02:00[Europe/Helsinki]
Notice how the hour changed from 14 to 16 because at that moment the clocks in Finland were running two hours ahead of UTC.
but it outputs wrong date Mon Oct 31 16:19:56 when it must be 12:19:56?
No the hour 14 is in UTC. Eastern Europe runs ahead of UTC, not behind it. As seen above, Finland on that day was running two hours ahead, so the little hand on the clocks of Finland were pointing at 4 (16 hour) rather than 12.
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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Use Joda Time. It's recommended by many StackOverflow users and is well documented with examples on timezone conversion.
Good luck!
What's the whole output? Date.toString() should print time zone. Maybe it's not in UTC in your case.
Lets say I have a string that represents a date that looks like this:
"Wed Jul 08 17:08:48 GMT 2009"
So I parse that string into a date object like this:
DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZ yyyy");
Date fromDate = (Date)formatter.parse(fromDateString);
That gives me the correct date object. Now I want to display this date as a CDT value.
I've tried many things, and I just can't get it to work correctly. There must be a simple method using the DateFormat class to get this to work. Any advice? My last attempt was this:
formatter.setTimeZone(toTimeZone);
String result = formatter.format(fromDate);
Use "zzz" instead of "ZZZ": "Z" is the symbol for an RFC822 time zone.
DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
Having said that, my standard advice on date/time stuff is to use Joda Time, which is an altogether better API.
EDIT: Short but complete program:
import java.text.*;
import java.util.*;
public class Test
{
public List<String> names;
public static void main(String [] args)
throws Exception // Just for simplicity!
{
String fromDateString = "Wed Jul 08 17:08:48 GMT 2009";
DateFormat formatter = new SimpleDateFormat
("EEE MMM dd HH:mm:ss zzz yyyy");
Date fromDate = (Date)formatter.parse(fromDateString);
TimeZone central = TimeZone.getTimeZone("America/Chicago");
formatter.setTimeZone(central);
System.out.println(formatter.format(fromDate));
}
}
Output: Wed Jul 08 12:08:48 CDT 2009
Using:
formatter.setTimeZone(TimeZone.getTimeZone("US/Central"));
outputs:
Wed Jul 08 12:08:48 CDT 2009
for the date in your example on my machine. That is after substituting zzz for ZZZ in the format string.
Sorry for digging out an old-thread. But I was wondering if there is a java-class that holds all the time-zone-ids as a constant class.
So instead of having to hard-code the time-zone-id while setting time-zone like this:
formatter.setTimeZone(TimeZone.getTimeZone("US/Central"));
we would instead be doing something more standard/uniform:
formatter.setTimeZone(TimeZone.getTimeZone(SomeConstantClass.US_CENTRAL));
where SomeConstantClass.java is a class that holds the constants referring to the different time-zone-ids that are supported by the TimeZone class.
The modern way is with the java.time classes.
ZonedDateTime
Specify a formatting pattern to match your input string. The codes are similar to SimpleDateFormat but not exactly. Be sure to read the class doc for DateTimeFormatter. Note that we specify a Locale to determine what human language to use for name of day-of-week and name of month.
String input = "Wed Jul 08 17:08:48 GMT 2009";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss z uuuu" , Locale.ENGLISH );
ZonedDateTime zdt = ZonedDateTime.parse ( input , f );
zdt.toString(): 2009-07-08T17:08:48Z[GMT]
We can adjust that into any other time zone.
Specify a proper time zone name in the format of continent/region. Never use the 3-4 letter abbreviation such as CDT or EST or IST as they are not true time zones, not standardized, and not even unique(!).
I will guess that by CDT you meant a time zone like America/Chicago.
ZoneId z = ZoneId.of( "America/Chicago" );
ZonedDateTime zdtChicago = zdt.withZoneSameInstant( z );
zdtChicago.toString() 2009-07-08T12:08:48-05:00[America/Chicago]
Instant
Generally best to work in UTC. For that extract an Instant. 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).
This Instant class is a basic building-block class of java.time. You can think of ZonedDateTime as an Instant plus a ZoneId.
Instant instant = zdtChicago.toInstant();
instant.toString(): 2009-07-08T17:08:48Z
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, & java.text.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 ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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.