SimpleDateFormat and TimeZone format - java

I am trying to make the SimpleDateFormat class to do what I need without success.
Here is the date format I need:
Fri 29 May 2015 10:22:30 GMT-0400 (Eastern Daylight Time)
Here is the closest format definition I was able to come with:
SimpleDateFormat("EEE dd MM yyyy HH:mm:ss Z (zzzz)", Locale.ENGLISH)
This will output:
Fri 29 May 2015 10:22:30 -0400 (Eastern Daylight Time)
Is there a formatting that can do what I need or do I have no other choice than manipulating the String to insert the missing GMT tag?

You can add the literal GMT surrounded by quotes:
new SimpleDateFormat("EEE dd MM yyyy HH:mm:ss 'GMT'Z (zzzz)", Locale.ENGLISH);

Try using EEE dd MM yyyy HH:mm:ss zZ (zzzz)
Working example

java.time
I recommend you use the modern date-time API*.
Using the available symbols, the closest match can be obtained with the pattern, EEE dd MMM uuuu HH:mm:ss OOOO (zzzz). However, it will display a : as the separator in the timezone offset. If you want the exact format, you can use the pattern, EEE dd MMM uuuu HH:mm:ss 'GMT'XX (zzzz) in which GMT has been used as a String literal.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.of(2015, Month.MAY, 29), LocalTime.of(10, 22, 30),
ZoneId.of("America/New_York"));
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("EEE dd MMM uuuu HH:mm:ss OOOO (zzzz)", Locale.ENGLISH);
String formatted1 = dtf1.format(zdt);
System.out.println(formatted1);
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("EEE dd MMM uuuu HH:mm:ss 'GMT'XX (zzzz)", Locale.ENGLISH);
String formatted2 = dtf2.format(zdt);
System.out.println(formatted2);
}
}
Output:
Fri 29 May 2015 10:22:30 GMT-04:00 (Eastern Daylight Time)
Fri 29 May 2015 10:22:30 GMT-0400 (Eastern Daylight Time)
Learn more about the 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.

Related

Java Convert Time to iso_instant

I have strings like Thu Feb 04 21:25:12 CET 2021 and Sat Oct 03 11:57:00 CEST 2020
and I need to convert it to ISO_Instant time but my code doesn't work.
I hope someone can help me.
My Code:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz uuuu");
Instant ist = OffsetDateTime.parse("Thu Feb 04 19:03:27 CET 2021", dtf).toInstant();
Your date-time string has timezone Id instead of timezone offset and therefore you should parse it into ZonedDateTime. Also, Never use SimpleDateFormat or DateTimeFormatter without a Locale.
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz uuuu", Locale.ENGLISH);
Instant instant = ZonedDateTime.parse("Thu Feb 04 19:03:27 CET 2021", dtf).toInstant();
System.out.println(instant);
instant = ZonedDateTime.parse("Sat Oct 03 11:57:00 CEST 2020", dtf).toInstant();
System.out.println(instant);
}
}
Output:
2021-02-04T18:03:27Z
2020-10-03T09:57:00Z
Learn more about java.time, 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.

Problems with parsing dates using DateUtils

I am trying to parse various slightly different date strings for an Android application.
Two examples are:
Thu, 20 Aug 2020 13:30:16 +0000
Wed, 19 Aug 2020 15:28:47 GMT
Here is how I tried parsing these Strings:
Date pubDate = org.apache.commons.lang3.time.DateUtils.parseDate(dateString,
"EEE, dd MMM yyyy HH:mm:ss Z", "EEE, dd MMM yyyy HH:mm:ss zzz");
As far as I can tell this should work, but I am getting java.text.ParseException: Unable to parse the date: Wed, 19 Aug 2020 15:28:47 GMT exceptions for both those examples. What am I doing wrong here?
Your format is built into java.time
Use DateTimeFormatter.RFC_1123_DATE_TIME; it works for both of your strings. It’s really the same format, only with the offset from UTC (or GMT) denoted differently. DateTimeFormatter is part of java.time, the modern Java date and time API. I recommend that you prefer java.time over Date and DateUtils, also because the Date class is poorly designed and long outdated.
String s = "Thu, 20 Aug 2020 13:30:16 +0000";
OffsetDateTime dt = OffsetDateTime.parse(s, DateTimeFormatter.RFC_1123_DATE_TIME);
System.out.println(dt);
Output is:
2020-08-20T13:30:16Z
Let’s try with your other string example:
String s = "Wed, 19 Aug 2020 15:28:47 GMT";
2020-08-19T15:28:47Z
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
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.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Your time zones are in 2 different formats:
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
The first one looks like it follows the format:
EEE, dd MMM yyyy HH:mm:ss Z", "EEE, dd MMM yyyy HH:mm:ss Z
While the second is of the format:
EEE, dd MMM yyyy HH:mm:ss Z", "EEE, dd MMM yyyy HH:mm:ss z
I do not see any problem with your formats.
Demo:
import java.text.ParseException;
import java.util.Date;
public class Main {
public static void main(String[] args) throws ParseException {
String[] dateStrings = { "Wed, 19 Aug 2020 15:28:47 GMT", "Thu, 20 Aug 2020 13:30:16 +0000" };
for (String dateString : dateStrings) {
Date pubDate = org.apache.commons.lang3.time.DateUtils.parseDate(dateString, "EEE, dd MMM yyyy HH:mm:ss Z",
"EEE, dd MMM yyyy HH:mm:ss zzz");
System.out.println(pubDate);
}
}
}
Output:
Wed Aug 19 16:28:47 BST 2020
Thu Aug 20 14:30:16 BST 2020
However, I strongly suggest you stop using the outdated and error-prone java.util date-time API and SimpleDateFormat. Switch to the modern java.time date-time API and the corresponding formatting API (java.time.format). Learn more about the modern date-time API from Trail: Date Time.
Using 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) {
// Test strings
String[] dateStrings = { "Wed, 19 Aug 2020 15:28:47 GMT", "Thu, 20 Aug 2020 13:30:16 +0000" };
// Define formatter
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("[EEE, dd MMM yyyy HH:mm:ss Z][EEE, dd MMM yyyy HH:mm:ss zzz]", Locale.ENGLISH);
for (String dateString : dateStrings) {
ZonedDateTime zdt = ZonedDateTime.parse(dateString, formatter);
System.out.println(zdt);
}
}
}
Output:
2020-08-19T15:28:47Z[GMT]
2020-08-20T13:30:16Z
If your android version is not compliant with Java-8, you can backport using ThreeTen-BackportCheck. Check How to use ThreeTenABP in Android Project

Joda time gives parse Exception for BST timezone but not for GMT [duplicate]

This question already has an answer here:
Joda DateTimeFormatter.parseDateTime is failing for General time zone('z')
(1 answer)
Closed 2 years ago.
I'm trying to compare current date with an input date, received in this format "EEE MMM dd HH:mm:ss zzz yyyy"
This piece of code works when my input string is Wed Apr 01 09:00:00 GMT 2020 but doesn't work if its Wed Apr 01 09:00:00 BST 2020 .
DateTime currentTime =DateTime.now().withZone(DateTimeZone.forID("Europe/London"));
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss zzz yyyy");
DateTime inputDateTime = fmt.parseDateTime("Wed Apr 01 09:00:00 BST 2020");
if (inputDateTime.isBefore(currentTime))
Log.d(TAG, "if ");
else
Log.d(TAG, "else ");
Any idea on what am I doing wrong? Also, feel free to suggest if there's a better way to do it (can't use new Java date and time library, since we support android API 19+ )
If you use ThreeTen Android Backport instead of Joda-Time, and you should, then it parses fine:
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy");
ZonedDateTime inputDateTime = ZonedDateTime.parse("Wed Apr 01 09:00:00 BST 2020", fmt);
System.out.println(inputDateTime);
Output
2020-04-01T09:00+01:00[Europe/Isle_of_Man]
Docs has mentioned that Time zone names cannot be parsed in joda DateTimeFormat because time zone abbreviations are ambiguous and the parser can't know which time zone it is exactly
Zone names: Time zone names ('z') cannot be parsed.
For example
BST can be British Summer Time or Bangladesh Standard Time or Bougainville Standard Time
PST can be Pacific Standard Time or Pakistan Standard
Time
CST could be Central Standard Time (USA), China Standard Time, or Cuba Standard Time
EST could be Eastern Standard Time (USA), or Eastern Standard Time (Australia).
And the best way to is to replace BST with appropriate iso timezone code here (for example Europe/Isle_of_Man), and then simple use "EEE MMM dd HH:mm:ss ZZZ yyyy" DateTimeFormat
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss ZZZ yyyy");
DateTime inputDateTime = fmt.parseDateTime("Wed Apr 01 09:00:00 Europe/Isle_of_Man 2020");
System.out.println(inputDateTime); //2020-04-01T09:00:00.000+01:00
I'm not sure if this meets your requirements for the Andriod API 19+, but here is something for the date formatting with SimpleDateFormatter
String pattern = "EEEEE MMMMM yyyy HH:mm:ss";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
String date = simpleDateFormat.format(new Date());
System.out.println(date);
Hope this solves your problem!

Unparsable Date Exception : SimpleDateFormat

am getting date as string
String dateStr = Mon Mar 31 2014 00:00:00 GMT+0530 (India Standard Time)
but am getting unparsable date exception when am tring to parse using SimpleDateFormat
java.util.Date date = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss Z", Locale.ENGLISH).parse(dateStr);
please help me to solve this
The "GMT" part is confusing things - the Z format specifier expects just "0800" or similar.
You can change your format to:
"EEE MMM dd yyyy HH:mm:ss 'GMT'Z"
and that will work. (It's ignoring the time zone name at the end of the string, of course.)
This'll work:
java.util.Date date = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z", Locale.ENGLISH).parse(dateStr);
java.time
The legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) are outdated and error-prone. It is recommended to stop using them completely and switch to java.time, the modern date-time API*.
Demo using modern date-time API:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;
public class Main {
public static void main(String args[]) {
String dateStr = "Mon Mar 31 2014 00:00:00 GMT+0530 (India Standard Time)";
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("EEE MMM d u H:m:s")
.appendLiteral(' ')
.appendZoneId()
.appendPattern("X")
.appendLiteral(" (")
.appendZoneText(TextStyle.FULL)
.appendLiteral(')')
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(dateStr, dtf);
System.out.println(zdt);
}
}
Output:
2014-03-31T00:00+05:30[Asia/Kolkata]
For any reason, if you need an object of java.util.Date from this object of ZonedDateTime, you can so as follows:
Date date = Date.from(zdt.toInstant());
Learn more about the 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.

Getting Date in HTTP format in Java

I'm trying to get a String of a date in Java in the format specified in HTTP 1.1. Which, as far as I can tell, is:
Fri, 31 Dec 1999 23:59:59 GMT
With the time always being GMT.
What would be the easiest way to get this from Date/Calendar/?
java.time
EDIT:
DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH).withZone(ZoneId.of("GMT"))
is the way to do it with pure java.time. HTTP 1.1 is to not a 100% match with RFC 1123, so using the java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME formatter will fail for day-of-month less than 10. (thanks to #PavanKamar and #ankon for pointing that out)
Note: to be backwards compliant, you would need to also support the other two formats specified by RFC 2616
In case someone else will try to find the answer here (like I did) here's what will do the trick:
String getServerTime() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
return dateFormat.format(calendar.getTime());
}
in order to set the server to speak English and give time in GMT timezone.
If you're using Joda-Time (which I would highly recommend for any handling of dates and times in Java), you can do:
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
...
private static final DateTimeFormatter RFC1123_DATE_TIME_FORMATTER =
DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'")
.withZoneUTC().withLocale(Locale.US);
...
RFC1123_DATE_TIME_FORMATTER.print(new DateTime())
Two-digit day-of-month
Some applications require the format to include a two digit day-of-month as per RFC7231. The Java 8 DateTimeFormatter.RFC_1123_DATE_TIME uses a single digit:
System.out.println(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneOffset.UTC)));
Output: Wed, 1 Aug 2018 14:56:46 GMT
Some applications don't like that. Before you use the old answers that use Joda-time or a pre-java8 SimpleDateFormat, here's a working Java-8 DateTimeFormatter:
DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss O")
Now, when you do this:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss O");
System.out.println(formatter.format(ZonedDateTime.now(ZoneOffset.UTC)));
You get Wed, 01 Aug 2018 14:56:46 GMT - note the leading zero in the day-of-month field.
If you, like me, are trying to format a Java 8 java.time.Instant you need to explicitly add the time zone to the formatter. Like this:
Instant instant = Instant.now();
String formatted = DateTimeFormatter.RFC_1123_DATE_TIME
.withZone(ZoneOffset.UTC)
.format(instant);
System.out.println(formatted);
Which prints:
Tue, 15 Mar 2016 14:45:34 GMT
If you are not afraid of additional dependencies, you can use apache DateUtils:
import org.apache.http.impl.cookie.DateUtils;
DateUtils.formatDate(new Date(System.currentTimeMillis()));
// Tue, 17 Apr 2012 18:59:02 GMT
This will format your date with respect to RFC 822 RFC1123.
I know this is a late response but just wanted to add it for completeness.
You did not mention what you need the string for. But if you need it for an HTTP response header, you can use HttpServletResponse.setDateHeader(). It does all the formatting for you.
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
System.out.println("Date: " + dateFormat.format(calendar.getTime()));
You can play with it. The documentation is here:
http://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

Categories