Getting Date in HTTP format in Java - 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

Related

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!

SimpleDateFormat parse

I have an issue with SimpleDateFormat:
Error:
Unparseable date: "Thu, 09 Nov 2017 16:17:42 GMT"
Code:
DF_SERVER_FORMAT="EEE, dd MMM yyyy HH:mm:ss'Z'"
....
var formater=SimpleDateFormat(DF_SERVER_FORMAT)
formater.parse(source)
as per SimpleDateFormat documentation, Z (capitalized) is for an RFC 822 time zone, e.g. -0800
for a General time zone use z.
this should work:
DF_SERVER_FORMAT="EEE, dd MMM yyyy HH:mm:ss z"
Try "EEE, d MMM yyyy HH:mm:ss z" this pattern works for me.
You can try to format some date using your pattern, to see the difference and then fix your pattern accordingly. Here is what I did in J2SE:
SimpleDateFormat df = new SimpleDateFormat("EEE dd MMM yyyy HH:mm:ss'Z'");
System.out.println(df.format(new Date()));
This is producing:
Thu 09 Nov 2017 17:49:07Z
But, when I used the pattern "EEE, dd MMM yyyy HH:mm:ss z", it produced the expected result:
Thu, 09 Nov 2017 17:51:09 CET
For anyone who either is fine with an external dependency (temporarily) or is using Java 8 or later I wanted to contribute the modern answer. Because I consider SimpleDateFormat long outdated.
The modern Java date and time API is generally much nicer to work with. In addition, your string is in RFC 1123 format, and the modern API comes with a formatter for this format. So no need to build your format pattern string yourself (my code is pure Java, I trust you to adopt to Kotlin):
String dateString = "Thu, 09 Nov 2017 16:17:42 GMT";
OffsetDateTime dateTime = OffsetDateTime.parse(dateString,
DateTimeFormatter.RFC_1123_DATE_TIME);
This produces an OffsetDateTime of 2017-11-09T16:17:42Z as expected.
To use this on Android, get ThreeTenABP, see this question: How to use ThreeTenABP in Android Project. Java 8 and later come with the modern API built-in. If using Java 6 or 7 on non-Android, you need the ThreeTen Backport.
What went wrong in your code? With your format pattern string you were asking for a literal Z right after the seconds, with no space in between. Since your input string didn’t have a Z there, parsing failed (instead it had a space and the offset ID GMT). In addition, your code seems to be sensitive to locale: if your default locale is one where the abbreviation for Thursday is not Thu or for November not Nov, parsing will fail (in contrast, RFC_1123_DATE_TIME expects (and requires) day and month abbreviations in English independently of locale).

Java simpledateformat Unparseable date, even though the format appears to be right

I've got a silly problem, here's my code:
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zZ",Locale.US);
System.out.println(dateFormat.format(new Date()));
try {
wou.setDateStart(dateFormat.parse(date));
wou.setDateEnd(dateFormat.parse(date));
} catch (ParseException e) {
System.out.println(e.getCause() + " " + e.getMessage());
e.printStackTrace();
}
the result is following:
Fri Jun 05 2015 15:34:29 GMT+0000
null Unparseable date: "Fri Jun 05 2015 17:30:00 GMT+0000"
What's wrong with my format? It outputs the current date in the same format as the date I want to parse, but keeps telling me that the date is unparseable...
I'm struggling that for over an hour and I'm completely lost...
EDIT:
I have no control over the date I need to parse (if I did, I would change it in a source to a format that I could consume)
Following code:
String date = request.getParameter("absencyDate");
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss z",Locale.US);
try {
System.out.println(dateFormat.format(new Date()));
System.out.println(date);
System.out.println(dateFormat.parse(date));
} catch (ParseException e1) {
Produces same error:
Fri Jun 05 2015 16:09:15 GMT
Fri Jun 05 2015 12:30:00 GMT+0000
java.text.ParseException: Unparseable date: "Fri Jun 05 2015 12:30:00 GMT+0000"
The problem is your use of zZ in the date format. It expects a simple name-based zone (z), followed by an RFC-822 zone (Z).
It works well if the default zone (or the zone set in the format) is not GMT, because then it just parses up to that point (matches the z), and then it parses the +0000 as the Z.
But when the zone is GMT, it actually tries to parse the part that follows it (+0000) as part of the z, because "GMT+hh:mm" is a valid zone for z, and that fails.
The date format appears deceivingly correct. But combining two timezone formats is not. It should either be a named time zone (which includes "GMT+00:00"), or an RFC 822 offset (which doesn't include the "GMT" designation).
Edit following OP edit
So you get your date parameter from somewhere, and they are sending it to you with a non-standard zone designation. GMT+0000 matches neither general time zone (should be GMT or GMT+00:00), RFC 822 time zone (should be +0000 without GMT), nor ISO 8601 time zone (should be +00 or +0000 or +00:00).
If you know that they will always be using GMT in their dates, I think the best you can do is:
"EEE MMM dd yyyy HH:mm:ss 'GMT'Z"
Which will take the GMT part as a literal string rather than a time zone designator, then interpret the time zone from whatever follows it.
Or if the source that generates that parameter is under your control, fix its format to use a proper time zone matching one of the standards.
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.util.Locale;
public class Main {
public static void main(String args[]) {
String dateStr = "Fri Jun 05 2015 17:30:00 GMT+0000";
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("EEE MMM d u H:m:s")
.appendLiteral(' ')
.appendZoneId()
.appendPattern("X")
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(dateStr, dtf);
System.out.println(zdt);
}
}
Output:
2015-06-05T17:30Z[GMT]
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.

SimpleDateFormat and TimeZone format

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.

How to convert this "Tue Nov 13 14:35:04 +0000 2012" String format to date in Java?

How to convert the date Tue Nov 13 14:35:04 +0000 2012 String format to date in Java?
I know of Date.parse(String) but I don't know which format I should use for the date. Do I have to modify the string so that it can be parsed into date, and if yes then how?
Use SimpleDateFormat, with a format string of
"E MMM dd HH:mm:ss Z yyyy"
You should explicitly use Locale.US assuming these will definitely use English month/day names. (You don't want to be trying to parse French names just because the default locale is French, for example.)
Also, don't forget that the Date value returned will have no knowledge of the original time zone - it will have the right value for the instant represented in the original text, but don't expect the result of calling toString() to use the same zone - Date.toString() always uses the default time zone.
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.US);
Date test = sdf.parse("Tue Nov 13 14:35:04 +0000 2012");
System.out.print(test.toString());

Categories