SimpleDateFormat throws ParseException With Error Offset 0 - java

What's wrong with the following code? It throws a ParseException with error offset 0.
final DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");
df.parse("Thu Jan 23 14:24:47 2014");

If you don't specify a Locale to the formatter when you construct it, it uses your default Locale which apparently doesn't spell days and months in English.
So specify one to the formatter that does.
final DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.UK);

Is your locale "EN"? If you use English names for the date, make sure you are using that locale

SimpleDateFormat is absolutely locale-sensitive. Certain fields, like hours and minutes, are locale-independent.
SimpleDateFormat also supports localized date and time pattern strings. In these strings, the pattern letters described above may be replaced with other, locale dependent, pattern letters. SimpleDateFormat does not deal with the localization of text other than the pattern letters; that's up to the client of the class.
Or, you can use the localization-friendly DateFormat#getDateInstance() factory method instead, since:
public SimpleDateFormat(String pattern, Locale locale)
Constructs a SimpleDateFormat using the given pattern and the default date format symbols for the given locale. Note: This constructor may not support all locales. For full coverage, use the factory methods in the DateFormat class.
Source: https://stackoverflow.com/a/5174712/2591612

Never use SimpleDateFormat or DateTimeFormatter without a Locale
Since the given date-time is in English, you should use Locale.ENGLISH with your date-time parser; otherwise the parsing will fail in a system (computer, phone etc.) which is using a non-English type of locale.
Also, note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Demo:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Thu Jan 23 14:24:47 2014";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss uuuu", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
System.out.println(ldt);
}
}
Output:
2014-01-23T14:24:47
By default, DateTimeFormatter#ofPattern uses the default FORMAT locale which the JVM sets during startup based on the host environment. Same is the case with SimpleDateFormat. I have tried to illustrate the problem through the following demo:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Thu Jan 23 14:24:47 2014";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss uuuu");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
// Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtfWithEnglishLocale = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss uuuu", Locale.ENGLISH);
System.out.println("JVM's Locale: " + Locale.getDefault());
System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss uuuu");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
}
}
Output:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2014-01-23T14:24:47
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2014-01-23T14:24:47
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Thu Jan 23 14:24:47 2014' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
at Main.main(Main.java:33)
The following demo, using SimpleDateFormat, is just for the sake of completeness:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
final String strDateTime = "Thu Jan 23 14:24:47 2014";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
System.out.println(date);
}
}
Output:
Thu Jan 23 14:24:47 GMT 2014

Related

java parse date GRAVE null

In this code,
String str="Sun Feb 07 00:27:16 CET 2021";
SimpleDateFormat sdf=new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy");
try {
java.util.Date date=sdf.parse(str);
System.out.print(date.getTime());
} catch (ParseException ex) {
Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
}
It shows
GRAVE: null
java.text.ParseException: Unparseable date: "Sun Feb 07 00:27:16 CET 2021"
How to solve it plz!
There are two problems with your code:
Not using the correct format: you have used E instead of EEE
Not using Locale: make it a habit to use the applicable Locale with date-time parsing/formatting API. Your date-time string is in English and therefore you should use an English-specific locale e.g. Locale.ENGLISH, Locale.US etc.
Correct code:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
String str = "Sun Feb 07 00:27:16 CET 2021";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
java.util.Date date = sdf.parse(str);
System.out.print(date.getTime());
}
}
Output:
1612654036000
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Using the modern date-time API:
import java.text.ParseException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
String str = "Sun Feb 07 00:27:16 CET 2021";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(str, dtf);
System.out.println(zdt);
System.out.println(zdt.toInstant().toEpochMilli());
}
}
Output:
2021-02-07T00:27:16+01:00[Europe/Paris]
1612654036000
Learn more about the modern date-time API from Trail: Date Time.

ZonedDateTime.parse() fails for exact the same string in Windows but works in Mac and Linux

The following UnitTest is failing when being executed through IntelliJ IDE in a Windows machine (Java 11.0.9) but passes when executed in a Mac or Linux machine with the same version of Java.
#Test
public void rfc1123JaveTimeUtilParsing(){
final String rfc1123Pattern = "EEE, dd MMM yyyy HH:mm:ss z";
final String responseTimeStamp = "Mon, 14 Dec 2020 20:34:37 GMT";
DateTimeFormatter javaTimeDateTimeFormatter = DateTimeFormatter.ofPattern(rfc1123Pattern);
ZonedDateTime javaFinalTime = ZonedDateTime.parse(responseTimeStamp, javaTimeDateTimeFormatter);
Assert.assertNotNull(javaFinalTime);
}
For windows the result is the following exception:
java.time.format.DateTimeParseException: Text 'Mon, 14 Dec 2020 20:34:37 GMT' could not be parsed at index 0
Never use DateTimeFormatter without a Locale.
Since the given date-time is in English, you should use the DateTimeFormatter with Locale.ENGLISH.
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String responseTimeStamp = "Mon, 14 Dec 2020 20:34:37 GMT";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(responseTimeStamp, dtf);
System.out.println(zdt);
}
}
Output:
2020-12-14T20:34:37Z[GMT]
By default, DateTimeFormatter#ofPattern uses the default FORMAT locale which the JVM sets during startup based on the host environment. I have tried to illustrate the problem through the following demo:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String responseTimeStamp = "Mon, 14 Dec 2020 20:34:37 GMT";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + ZonedDateTime.parse(responseTimeStamp, dtfWithDefaultLocale));
// DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(responseTimeStamp, dtf);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
System.out.println("JVM's Locale: " + Locale.getDefault());
// DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + ZonedDateTime.parse(responseTimeStamp, dtfWithDefaultLocale));
}
}
Output:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2020-12-14T20:34:37Z[GMT]
Parsed with Locale.ENGLISH: 2020-12-14T20:34:37Z[GMT]
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Mon, 14 Dec 2020 20:34:37 GMT' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
at Main.main(Main.java:29)

Unparseable date with symbolic timezone [duplicate]

I'm always getting the parse exception even if the format to check and the string value are same.
Here is the code:
String format = "EEE MMM dd HH:mm:ss z yyyy";
String value = "Mon Sep 18 10:30:06 MST 2017";
public static boolean isValidFormat(String format, String value) {
Date date = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat(format);
date = sdf.parse(value); // here it breaks
if (!value.equals(sdf.format(date))) {
date = null;
}
} catch (ParseException ex) {
ex.printStackTrace(); //java.text.ParseException: Unparseable date:
"Mon Sep 18 10:30:06 MST 2017" (at offset 0)
}
return date != null;
}
It says that your date-time string is unparseable at index 0. Index 0 is where it says Mon, so the three letter time zone abbreviation is not the first suspect. The locale is. “Mon” works as abbreviation for Monday in English, but not in very many other languages. So if your device has a non-English language setting — maybe it has even been changed recently — this will fully explain your observation.
The shortsighted solution is
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ROOT);
I use Locale.ROOT to mean that no language specific processing should be done. If your string is in English because English is generally the language used in computing around the globe, I would consider this choice appropriate. If on the other hand it is in English because it comes from an English speaking locale, that locale will be the right one to use.
With this change, on my computer your code formats your date into Mon Sep 18 11:30:06 MDT 2017, which, as you can see is not the same as the value we started out from, so your method returns false. My JVM understood MST as Mountain Standard Time, and then assumed summer time (DST) in September and formatted the string accordingly.
ThreeTenABP
That said, Date and SimpleDateFormat are long outdated classes. You should give it a thought to get rid of them and use the modern Java date and time API instead. On Android you get it in the ThreeTenABP, see this question: How to use ThreeTenABP in Android Project. Now you may do:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format, Locale.ROOT);
try {
return ZonedDateTime.parse(value, dtf).format(dtf).equals(value);
} catch (DateTimeParseException dtpe) {
dtpe.printStackTrace();
return false;
}
This behaves the same as above.
Three letter time zone abbreviations
You should avoid the three and four letter time zone abbreviations where you can. They are not standardized and generally ambiguous. MST, for example, may mean Malaysia Standard Time or Mountain Standard Time. The latter isn’t even a full time zone, since MDT is used for the greater part of the year, which caused the trouble I observed as I said above.
Instead, see if you can get a string in ISO 8601 format, like 2017-09-18T10:30:06+08:00. Second best, just get something unambiguous. One way is to include an offset from UTC rather than a time zone ID (or both).
Never use SimpleDateFormat or DateTimeFormatter without a Locale
Since the given date-time is in English, you should use Locale.ENGLISH with your date-time parser; otherwise the parsing will fail in a system (computer, phone etc.) which is using a non-English type of locale.
Also, note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Demo:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Mon Sep 18 10:30:06 MST 2017";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
}
}
Output:
2017-09-18T10:30:06-06:00[America/Denver]
An important note about timezone before we proceed further:
Avoid specifying a timezone with the 3-letter abbreviation. A timezone should be specified with a name in the format, Region/City e.g. ZoneId.of("Europe/London"). With this convention, the ZoneId for UTC can be specified with ZoneId.of("Etc/UTC"). A timezone specified in terms of UTC[+/-]Offset can be specified as Etc/GMT[+/-]Offset e.g. ZoneId.of("Etc/GMT+1"), ZoneId.of("Etc/GMT+1") etc.
There are some exceptional cases as well e.g. to specify the timezone of Turkey, we use
ZoneId.of("Turkey")
The following code will give you all the available ZoneIds:
// Get the set of all time zone IDs.
Set<String> allZones = ZoneId.getAvailableZoneIds();
You should ask your server application to provide you with the date-time using this convention e.g.
Mon Sep 18 10:30:06 America/Denver 2017
The above code, without any change, will work for this date-time string.
Coming back to the original topic:
By default, DateTimeFormatter#ofPattern uses the default FORMAT locale which the JVM sets during startup based on the host environment. Same is the case with SimpleDateFormat. I have tried to illustrate the problem through the following demo:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Mon Sep 18 10:30:06 America/Denver 2017";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out
.println("Parsed with JVM's default locale: " + ZonedDateTime.parse(strDateTime, dtfWithDefaultLocale));
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
// Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtfWithEnglishLocale = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu", Locale.ENGLISH);
System.out.println("JVM's Locale: " + Locale.getDefault());
System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtfWithEnglishLocale);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out
.println("Parsed with JVM's default locale: " + ZonedDateTime.parse(strDateTime, dtfWithDefaultLocale));
}
}
Output:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2017-09-18T10:30:06-06:00[America/Denver]
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2017-09-18T10:30:06-06:00[America/Denver]
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Mon Sep 18 10:30:06 America/Denver 2017' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
at Main.main(Main.java:32)
The following demo, using SimpleDateFormat, is just for the sake of completeness:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
final String strDateTime = "Mon Sep 18 10:30:06 MST 2017";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM d H:m:s z yyyy", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
System.out.println(date);
}
}
Output:
Mon Sep 18 18:30:06 BST 2017
Note: The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the milliseconds from the Epoch of January 1, 1970. When you print an object of java.util.Date, its toString method returns the date-time calculated from this milliseconds value. Since java.util.Date does not have timezone information, it applies the timezone of your JVM and displays the same. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFomrat and obtain the formatted string from it.
Here is the code of dateformatter which will hep you to convert your date into any time format.
public void setDate(String date) {
dateInput = (TextView) itemView.findViewById(R.id.dateText);
DateFormat inputFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
try {
dateData = inputFormat.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
DateFormat outputFormat = new SimpleDateFormat("pur your desirable format");
String outputString = outputFormat.format(dateData);
dateInput.setText(outputString);
}
I use the almost use the same code as you do with only slight difference in SimpleDateFormat instantiation.
public static final String DATE_FORMAT = "EEE MMM d yyyy z HH:mm:ss";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.ROOT);
simpleDateFormat.format(date);
It returns Mon Sep 18 2017 GMT+03:00 23:04:10.

java.text.ParseException: Unparseable date: java.text.DateFormat.parse(DateFormat.java:579)

I have problem with SimpleDateFormat.
SimpleDateFormat dtfmt=new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.getDefault());
Date dt=dtfmt.parse(deptdt);
In Android Emulator works fine but in phone I have this error:
W/System.err: java.text.ParseException: Unparseable date: "24 Oct 2016 7:31 pm" (at offset 3)
W/System.err: at java.text.DateFormat.parse(DateFormat.java:579)
Any solution?
Never use SimpleDateFormat or DateTimeFormatter without a Locale
Since the given date-time is in English, you should use Locale.ENGLISH with your date-time parser; otherwise the parsing will fail in a system (computer, phone etc.) which is using a non-English type of locale.
Also, note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Demo:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "24 Oct 2016 7:31 pm";
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive() // For case-insensitive (e.g. am, Am, AM) parsing
.appendPattern("d MMM uuuu h:m a") // Pattern conforming to the date-time string
.toFormatter(Locale.ENGLISH); // Locale
LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
System.out.println(ldt);
}
}
Output:
2016-10-24T19:31
By default, DateTimeFormatter#ofPattern uses the default FORMAT locale which the JVM sets during startup based on the host environment. Same is the case with SimpleDateFormat. I have tried to illustrate the problem through the following demo:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "24 Oct 2016 7:31 pm";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
// Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtfWithEnglishLocale = getDateTimeFormatterWithEnglishLocale();
System.out.println("JVM's Locale: " + Locale.getDefault());
System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
}
static DateTimeFormatter getDateTimeFormatterWithDefaultLocale() {
return new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("d MMM uuuu h:m a")
.toFormatter(); // Using default Locale
}
static DateTimeFormatter getDateTimeFormatterWithEnglishLocale() {
return new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("d MMM uuuu h:m a")
.toFormatter(Locale.ENGLISH); // Using Locale.ENGLISH
}
}
Output:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text '24 Oct 2016 7:31 pm' could not be parsed at index 3
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
at Main.main(Main.java:34)
The following demo, using SimpleDateFormat, is just for the sake of completeness:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
final String strDateTime = "24 Oct 2016 7:31 pm";
SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy h:m a", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
System.out.println(date);
}
}
Output:
Mon Oct 24 19:31:00 BST 2016
Your deptdt contains Oct which looks like an English month name.
But your Locale.getDefault() probably gives a non-english locale.
Replace it by Locale.ENGLISH or Locale.US:
SimpleDateFormat dtfmt=new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.ENGLISH);
Date dt=dtfmt.parse(deptdt);
It probably happens because the phone's default locale is not English, and the month name in your input is (Oct).
The solution is to explicity use the English locale:
SimpleDateFormat dtfmt = new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.ENGLISH);
Date dt = dtfmt.parse("24 Oct 2016 7:31 pm");
Instead of directly working with SimpleDateFormat (as this old API has lots of problems and design issues), you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To use it in Android, you'll also need the ThreeTenABP (more on how to use it here).
The main classes to be used are org.threeten.bp.LocalDateTime (it seems the best choice, as you have date and time fields in your input) and org.threeten.bp.format.DateTimeFormatter (to parse the input). I also use java.util.Locale class to make sure it parse the month names in English, and the org.threeten.bp.format.DateTimeFormatterBuilder to make sure it parses pm (make it case insensitive, as the default is PM):
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// case insensitive to parse "pm"
.parseCaseInsensitive()
// pattern
.appendPattern("dd MMM yyyy h:mm a")
// use English locale to parse month name (Oct)
.toFormatter(Locale.ENGLISH);
// parse input
LocalDateTime dt = LocalDateTime.parse("24 Oct 2016 7:31 pm", fmt);
System.out.println(dt); // 2016-10-24T19:31
The output will be:
2016-10-24T19:31
If you need to convert this to a java.util.Date, you can use the org.threeten.bp.DateTimeUtils class. But you also need to know what timezone will be used to convert this. In the example below, I'm using "UTC":
Date date = DateTimeUtils.toDate(dt.atZone(ZoneOffset.UTC).toInstant());
To change to a different zone, you can do:
Date date = DateTimeUtils.toDate(dt.atZone(ZoneId.of("Europe/London")).toInstant());
Note that the API uses IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard. To find the timezone that better suits each region, use the ZoneId.getAvailableZoneIds() method and check which one fits best for your use cases.
PS: the last example above (dt.atZone(ZoneId.of("Europe/London"))) will create the date/time 2016-10-24T19:31 in London timezone. But if what you want is 2016-10-24T19:31 in UTC, then convert it to another timezone, then you should do:
Date date = DateTimeUtils.toDate(dt
// first convert it to UTC
.toInstant(ZoneOffset.UTC)
// then convert to LondonTimezone
.atZone(ZoneId.of("Europe/London")).toInstant());

Java SimpleDateFormat Wrong Timezone after parsing

Why: When I give input date string with GMT timezone, SimpleDateFormat parses it and outputs EET timezone?
public static String DATE_FORMAT="dd MMM yyyy hh:mm:ss z";
public static String CURRENT_DATE_STRING ="31 October 2011 11:19:56 GMT";
...
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(simpleDateFormat.parseObject(CURRENT_DATE_STRING));
And the output is:
Mon Oct 31 13:19:56 EET 2011
rather than
Mon Oct 31 13:19:56 GMT 2011
You're printing out the result of Date.toString(). A Date doesn't have any concept of a timezone - it's just the number of milliseconds since the UTC Unix epoch. Date.toString() always uses the system default time zone.
Note that you shouldn't be expecting "Mon Oct 31 13:19:56 GMT 2011" given that you've given a time which specifies a GMT hour of 11, not 13.
If you want to use a specific time zone for printing, you should use another DateFormat for the printing, rather than using Date.toString(). (Date.toString() keeps causing confusion like this; it's really unfortunate.)
java.util.Date does not hold timezone information.
A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone.
Apart from this, there are a couple of problems with your code:
Use H instead of h for the 24-Hour format. The letter, h is used for the 12-Hour format (i.e. with AM/PM marker).
Even though MMM works for parsing the long name of the month (e.g. January) with SimpleDateFormat, it is meant for the 3-letter month name (e.g. Jan). If you try doing it with the modern Date-Time API, you will be greeted with the DateTimeParseException. You should use MMMM for the long name of the month.
Demo incorporating these points:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "31 October 2011 11:19:56 GMT";
SimpleDateFormat sdf = new SimpleDateFormat("dd MMMM yyyy HH:mm:ss z", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Date date = sdf.parse(strDateTime);
String strDate = sdf.format(date);
System.out.println(strDate);
// Some other format
sdf = new SimpleDateFormat("MMMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
strDate = sdf.format(date);
System.out.println(strDate);
// The last format with some other timezone
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
strDate = sdf.format(date);
System.out.println(strDate);
}
}
Output:
31 October 2011 11:19:56 GMT
October 31 11:19:56 GMT 2011
October 31 07:19:56 EDT 2011
ONLINE DEMO
Switch to java.time API.
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "31 October 2011 11:19:56 GMT";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MMMM uuuu HH:mm:ss z", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
// Some other format
DateTimeFormatter dtfAnother = DateTimeFormatter.ofPattern("MMMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
String strDate = dtfAnother.format(zdt);
System.out.println(strDate);
}
}
Output:
2011-10-31T11:19:56Z[GMT]
October 31 11:19:56 GMT 2011
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Categories