Inconsistent date parsing using SimpleDateFormat - java

I'm really scratching my head on this one. I've been using SimpleDateFormats with no troubles for a while, but now, using a SimpleDateFormat to parse dates is (only sometimes) just plain wrong.
Specifically:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = sdf.parse("2009-08-19 12:00:00");
System.out.print(date.toString());
prints the string Wed Aug 19 00:00:00 EDT 2009. What the heck? - it doesn't even parse into the wrong date all the time!
Update: That fixed it beautifully. Wouldn't you know it, that was misused in a few other places as well. Gotta love debugging other people's code :)

I think you want to use the HH format, rather than 'hh' so that you are using hours between 00-23. 'hh' takes the format in 12 hour increments, and so it assumes it is in the AM.
So this
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2009-08-19 12:00:00");
System.out.print(date.toString());
Should print out
Wed Aug 19 12:00:00 EDT 2009

The hour should be specified as HH instead of hh. Check out the section on Date and Time patterns in http://java.sun.com/javase/6/docs/api/java/text/SimpleDateFormat.html

You're printing out the toString() representation of the date, rather than the format's representation. You may also want to check the hour representation. H and h mean something different. H is for the 24 hour clock (0-23), h is for the 12 hour clock (1-12), (there is also k and K for 1-24 and 0-11 based times respectively)
You need to do something like:
//in reality obtain the date from elsewhere, e.g. new Date()
Date date = sdf.parse("2009-08-19 12:00:00");
//this format uses 12 hours for time
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//this format uses 24 hours for time
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.print(sdf.format(date));
System.out.print(sdf2.format(date));

tl;dr
LocalDateTime ldt = LocalDateTime.parse( "2009-08-19 12:00:00".replace( " " , "T" ) );
java.time
Other Answers are correct but use legacy date-time classes. Those troublesome old classes have been supplanted by the java.time classes.
Your input string is close to standard ISO 8601 format. Tweak by replacing the SPACE in the middle with a T. Then it can be parsed without specifying a formatting pattern. The java.time classes use ISO 8601 by default when parsing/generating Strings.
String input = "2009-08-19 12:00:00".replace( " " , "T" );
The input data has no info about offset-from-UTC or time zone. So we parse as a LocalDateTime.
LocalDateTime ldt = LocalDateTime.parse( input );
If by the context you know the intended offset, apply it. Perhaps it was intended for UTC (an offset of zero), where we can use the constant ZoneOffset.UTC.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC );
Or perhaps you know it was intended for a particular time zone. A time zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST).
ZonedDateTime zdt = ldt.atZone( ZoneId.of( "America/Montreal" ) );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome 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.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (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.

Related

Java date parsing not working for ET timezone while working for IST

I am trying to parse the String to date. String having date format as
"dd-MMM-yyyy Z" and String having value "12-DEC-2018 ET". Its giving the error
java.text.ParseException: Unparseable date: "12-DEC-2018 ET".
The same code is working for String having value "12-DEC-2018 IST".
below is the code snippet:
public static void main(String[] args) throws ParseException {
String dateInputIST ="12-DEC-2018 IST";
String dateInputET ="12-DEC-2018 ET";
SimpleDateFormat sdfmt1 = new SimpleDateFormat("dd-MMM-yyyy Z");
SimpleDateFormat sdfmt2= new SimpleDateFormat("dd/MM/yyyy");
Date dDate = sdfmt1.parse( dateInputIST );
String strOutput = sdfmt2.format( dDate );
System.out.println(strOutput);
Date etDate = sdfmt1.parse(dateInputET);
strOutput = sdfmt2.format(etDate);
System.out.println(strOutput);
}
Could someone please help. I needed to parse the time in any timezone.
Thanks,
Navin
Change
String dateInputET ="12-DEC-2018 ET";
to
String dateInputET ="12-DEC-2018 EDT";
'ET' is not a recognized time zone.
Pseudo-zones
ET, EST, and IST are not actually time zones. Those 2-4 letter pseudo-zones are not standardized and are not even unique! For example, IST can mean India Standard Time, Ireland Standard Time, Iceland Standard Time, and more.
Real time zone names take the format of Continent/Region such as Africa/Tunis.
Date & zone, separately
Date with time zone has no real meaning.
Handle the date as a LocalDate object.
String input = "12-DEC-2018"
DayeTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu" , Locale.US ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
Handle your desired time zone separately, as a ZoneId object.
ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
To combine, determine the first moment of the day.
ZonedDateTime zdtNewYork = ld.atStartOfDay( z ) ;
Generate text representing that moment in standard ISO 8601 format extended to append the name of the time zone in square brackets.
To see that same moment in UTC, extract a Instant.
Instant instant = zdtNewYork.toInstant() ;
Adjust into another zone.
ZonedDateTime zdtKolkata = instant.atZone( ZoneId.of( "Asia/Kolkata" ) ) ;
To focus on the date only, get a LocalDate for the day of that same moment when viewed through the lens of the wall-clock time used in India.
LocalDate ldKolkata = zdtKolkata.toLocalDate() ;
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.
java.time
DateTimeFormatter dateZoneFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("dd-MMM-uuuu v")
.toFormatter(Locale.ENGLISH);
String dateInputIST ="12-DEC-2018 IST";
String dateInputET ="12-DEC-2018 ET";
TemporalAccessor parsed = dateZoneFormatter.parse(dateInputIST);
System.out.println("Date: " + LocalDate.from(parsed) + " Time zone: " + ZoneId.from(parsed));
parsed = dateZoneFormatter.parse(dateInputET);
System.out.println("Date: " + LocalDate.from(parsed) + " Time zone: " + ZoneId.from(parsed));
On my computer the output from this snippet was:
Date: 2018-12-12 Time zone: Atlantic/Reykjavik
Date: 2018-12-12 Time zone: America/New_York
Format pattern letter v is for the generic time-zone name, that is, the name that is the same all year regardless of summer time (DST), for example Eastern Time or short ET.
If you want to control the interpretation of ambiguous time zone abbreviations (of which there are a lot), you may use the two-arg appendGenericZoneText​(TextStyle, Set<ZoneId>) where the second argument contains the preferred zones. Still better if there is a way for you to avoid relying on time zone abbreviations altogether since, as I said, they are very often ambiguous.
I am not sure what sense a date with a time zone makes, though.
As an additional point, always specify locale for your formatters so they will also work if the default locale is changed or one day your program runs in a JVM with a different default locale.
Avoid SimpleDateFormat and Date
I don’t think SimpleDateFormat will be able to parse your string. It’s just the same since that class is already long outdated and is renowned for being troublesome, so you should never want to use it anyway.

Unparseable date: "1/29/2014 11:45:00 AM" - Android

I have a problem with parsing the following date from string: "1/29/2014 11:45:00 AM"
I do it the following way:
String source = "1/29/2014 11:45:00 AM";
Date startDate;
String sdfPattern = "MM/dd/yyyy hh:mm:ss aa";
SimpleDateFormat sdf = new SimpleDateFormat(sdfPattern, Locale.getDefault());
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
this.startDate = sdf.parse(source);
Interestingly, this works fine in a java project, but not in android. The error message I get:
01-15 15:36:46.950: W/System.err(2713): java.text.ParseException: Unparseable date: "1/29/2014 11:45:00 AM" (at offset 19)
Can anybody tell me what I am doing wrong?
Your format string specifies that you'll provide a two-digit month, but you're only providing "1".
I suspect you want:
String sdfPattern = "M/d/yyyy hh:mm:ss aa";
Additionally, the "AM/PM" designator is locale-sensitive (as are the date and time separators) . If you know that it will always use English, you should say so:
SimpleDateFormat sdf = new SimpleDateFormat(sdfPattern, Locale.US);
Unless the data is actually entered by the user (or being formatted for the user) you should avoid Locale.getDefault().
Your default locale may not match the AM/PM marker in the input String causing the exception. Try using
SimpleDateFormat sdf = new SimpleDateFormat(sdfPattern, Locale.ENGLISH);
java.time
The Question and other Answers use the troublesome old legacy date-time classes bundled with the earliest versions of Java. Now supplanted by the java.time classes.
ISO 8601
By the way, use the ISO 8601 formats when generating Strings to represent date-time values for exchange with other software. Your format is ambiguous and trickier to parse, unlike the standard formats.
DateTimeFormatter
The codes defining a formatting pattern in java.time.DateTimeFormatter are similar to the outmoded SimpleDateFormat but not exactly. So read the doc carefully.
String input = "1/29/2014 11:45:00 AM";
Locale locale = Locale.ENGLISH; // For translating the “AM” & “PM”.
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "M/d/uuuu hh:mm:ss a" ).withLocale( locale );
LocalDateTime
Your input lacks any indication of an offset-from-UTC or a time zone. So we parse as a LocalDateTime object.
LocalDateTime ldt = LocalDateTime.parse ( input , f );
ldt.toString(): 2014-01-29T11:45
A LocalDateTime object purposely lacks any offset-from-UTC or time zone. That means it does not represent a moment on the timeline, only a rough idea about possible moments. You must assign an offset or time zone to give it meaning.
OffsetDateTime
If the context of your suggestions indicates this input was meant to be in UTC, apply the constant ZoneOffset.UTC to get an OffsetDateTime.
OffsetDateTime odt = ldt.atOffset ( ZoneOffset.UTC );
odt.toString(): 2014-01-29T11:45Z
ZonedDateTime
On the other hand, if the context indicates a specific time zone, apply a ZoneId to get a ZonedDateTime. The Questions seems to indicate that the Europe/London time zone is intended. Be aware that this time zone is not the same as UTC.
ZoneId z = ZoneId.of ( "Europe/London" );
ZonedDateTime zdt = ldt.atZone ( z );
zdt.toString(): 2014-01-29T11:45-05:00[America/Montreal]
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old 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.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (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.

Converting string to java.util.date

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

java GregorianCalendar adding hour strange behavior

I have a problem with GregorianCalendar so if you please can help me out with it. First I'll give you my code:
private String changeClock(String day, String clock, int change) {
String time="";
DateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm");
try {
Date d=df.parse(day+" "+clock);
GregorianCalendar g=new GregorianCalendar();
g.setTime(d);
g.add(GregorianCalendar.HOUR_OF_DAY, change);
time=g.get(GregorianCalendar.YEAR)+"-"
+(g.get(GregorianCalendar.MONTH)+1)+"-"
+g.get(GregorianCalendar.DAY_OF_MONTH)+" "
+g.get(GregorianCalendar.HOUR_OF_DAY)+":"
+g.get(GregorianCalendar.MINUTE);
} catch (Exception e) {
e.printStackTrace();
}
return time;
}
Let me explain what is happening. I have a GUI with + and - button. When someone press + it add one hour, or if - is pressed then take one hour.
Now example, time is 23:00 and I press +, it is everything ok and it jumps to 00:00 of the next day. Problems are on 12:00. If it is 12:00 and I press + it goes to 1:00 and that goes on and on. It doesn't move to the next day even after 2x12 hours or 21465x12 hours.
Moving backward is a little better if I can say so. When it is 00:00 and I press - it changes to yesterday 23:00 (also date changes). If I then press + it changes also one day forward (so to today in this case).
What have I done wrong or what more should I write to my code?
Thanks for your help guys.
Your date format is wrong...
You're using hh, which is a representation of the "Hour in am/pm (1-12)", so a time of 1pm is been converted to 1am instead.
You should be using HH which is a a representation of the "Hour in day (0-23)".
Either that, or you need supply a date/time format with the am/pm marker...
Using either DateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm"); or DateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm a");
Instead of relying on String date/time values, you should be passing in and back a Date object, leave the formatting for the display.
tl;dr
LocalDateTime.parse(
"2016-01-02 12:34:56".replace( " " , "T" )
)
Using java.time
The Answer by MadProgrammer is correct: Wrong code used in formatting pattern. But there is an even easier and better approach.
You are using troublesome old date-time classes now supplanted by the java.time classes.
Your input format in almost in standard ISO 8601 format. Just replace the SPACE in middle with a T.
String input = "2016-01-02 12:34:56".replace( " " , "T" );
The java.time classe use ISO 8601 formats by default. So need to specify a formatting pattern at all, so no formatting codes to get wrong.
LocalDateTime ldt = LocalDateTime.parse( input );
We parse as a LocalDateTime because the input lacks information about offset-from-UTC or time zone. If this value was meant for UTC, apply an offset to get an OffsetDateTime.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC );
If meant for some time zone, transform into a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( z );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old 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.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (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.

Java TimeZone conversions

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.

Categories

Resources