SimpleDateFormat produces different timezone outputs in Android vs JDK - java

There's a lot of questions on here on SimpleDateFormat but I can't seem to find anything on this issue. I'm running into issues with different output from the exact same code running on Android vs the JDK. I'm running in Eclipse and using the emulator to test Android. JDK version 1.7 and Android 4.4.
Any ideas on how to make Android output dates in the JDK style format?
TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
String RFC1123_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z";
final DateFormat rfc1123Format = new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US);
rfc1123Format.setTimeZone(GMT_ZONE);
String dateString = rfc1123Format.format(new Date());
JDK 1.7 dateString value: Fri, 20 Dec 2013 00:46:21 GMT
Android 4.4 dateString value: Fri, 20 Dec 2013 00:46:21 GMT+00:00

Android != Java
Android libraries are an imitation of the Java libraries but not exact copies. Thus the lawsuit between Oracle and Google. So you may see variations in behavior.
Joda-Time
If you want a consistent, and superior, experience when doing work with date-times, use the third-party open-source Joda-Time library. Joda-Time is meant to supplant the notoriously bad java.util.Date/Calendar classes.
JSR 310
Another option might be the Java 7 backport of JSR 310: Date and Time API java.time.* classes bundled with Java 8.
RFC 1123 Format
Regarding the follow-up question you added as a comment:
Any idea what pattern would produce the Fri, 20 Dec 2013 00:46:21 GMT format output on Android?
Surprisingly, Joda-Time 2.3 seems to lack a built-in formatter for that old RFC 1123 format. But the following home-brew format seems to do the job, provided you remember to convert the DateTime to UTC, as shown below.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTime nowInParis = new DateTime( DateTimeZone.forID( "Europe/Paris" ) );
DateTimeFormatter formatter = DateTimeFormat.forPattern("E, d MMM yyyy HH:mm:ss 'GMT'").withLocale( Locale.US );
String nowInParisAsStringGMT = formatter.print( nowInParis.toDateTime( DateTimeZone.UTC ) );
Dump to console…
System.out.println( "nowInParisAsStringGMT: " + nowInParisAsStringGMT );
System.out.println( "nowInParis: " + nowInParis );
When run…
nowInParisAsStringGMT: Fri, 20 Dec 2013 05:03:58 GMT
nowInParis: 2013-12-20T05:03:58.175+01:00

Here is a slightly modified version of Basil's answer for those who don't want to use Joda-Time:
private String toRfc1123(Date date) {
SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
return formatter.format(date);
}

Related

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).

Convert string to date (CEST works fine, GMT+02:00 doesn't work)

Question
Why is my Android app unable to parse String str1= "Tue Jun 20 15:56:29 CEST 2017"?
I found some similar questions, but none of them helped me.
Sidenotes
In my project I have some Java applications which are running on a computer and some Android applications. They are able to communicate to each other.
In the messages are timestamps. However my Java applications are sending timestamps in a format like String str1= "Tue Jun 20 15:56:29 CEST 2017" and my Android apps like String str2 = "Tue Jun 20 13:40:37 GMT+02:00 2017". To save the message including the time I have to parse the incoming time to a date.
My Android-App
In my Android app I can't parse the String str1= "Tue Jun 20 15:56:29 CEST 2017" correctly:
java.text.ParseException: Unparseable date: "Tue Jun 20 15:56:29 CEST 2017"
String str2 = "Tue Jun 20 13:40:37 GMT+02:00 2017"is working fine.
Code:
String str1 = "Tue Jun 20 14:53:08 CEST 2017";
SimpleDateFormat formatter = new SimpleDateFormat("EE MMM dd HH:mm:ss zzzz yyyy", Locale.US);
try {
Date date = formatter.parse(str1);
} catch (ParseException e) {
e.printStackTrace();
}
// test
String str2 = "Tue Jun 20 13:40:37 GMT+02:00 2017";
formatter = new SimpleDateFormat("EE MMM dd HH:mm:ss zzzz yyyy", Locale.US);
try {
Date date = formatter.parse(str2);
} catch (ParseException e) {
e.printStackTrace();
}
My Java-App
However, my Java application can parse both strings correctly.
Code:
String str = "Tue Jun 20 14:53:08 CEST 2017";
SimpleDateFormat formatter = new SimpleDateFormat("EE MMM dd HH:mm:ss zzzz yyyy", Locale.US);
try {
Date date = formatter.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
// test
str = "Tue Jun 20 13:40:37 GMT+02:00 2017";
formatter = new SimpleDateFormat("EE MMM dd HH:mm:ss zzzz yyyy", Locale.US);
try {
Date date = formatter.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
ThreeTen Solution
String to LocalDateTime
To convert my incoming string I'm using the following code:
String time = "Mon Jun 26 15:42:51 GMT 2017";
DateTimeFormatter gmtDateTimeFormatter = DateTimeFormatter.ofPattern("EE MMM dd HH:mm:ss 'GMT' yyyy", Locale.ENGLISH));
LocalDateTime timestamp = LocalDateTime.parse(time, gmtDateTimeFormatter);
LocalDateTime to String
To convert my LocalDateTime to a string I used this:
LocalDateTime timestamp = LocalDateTime.now();
DateTimeFormatter gmtDateTimeFormatter = DateTimeFormatter.ofPattern("EE MMM dd HH:mm:ss 'GMT' yyyy", Locale.ENGLISH));
String time = gmtDateTimeFormatter.format(timestamp);
Maybe there's a difference on how Android handles the zzzz pattern (probably Java's implementation handles it better than Android, so it "guesses" the correct timezone in a way that Android doesn't). I don't know.
Anyway, may I suggest you to avoid using those old classes? These old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
To parse both formats, you can use a DateTimeFormatter with optional sections. That's because CEST is a timezone short name and GMT+02:00 is an UTC offset, so if you want to parse both with the same formatter, you'll need to use one optional section for each format.
Another detail is that short names like CET or CEST are ambiguous and not standard. The new API uses IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
So, you need to choose one timezone that suits your needs. In the example below, I've just picked a timezone that's in CEST (Europe/Berlin), but you can change it according to what you need - you can get a list of all names using ZoneId.getAvailableZoneIds().
As the new API doesn't resolve CEST (because of its ambiguity), I need to create a set with the prefered timezone in order to correctly parse the input:
// when parsing, if finds ambiguous CET or CEST, it uses Berlin as prefered timezone
Set<ZoneId> set = new HashSet<>();
set.add(ZoneId.of("Europe/Berlin"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// your pattern (weekday, month, day, hour/minute/second)
.appendPattern("EE MMM dd HH:mm:ss ")
// optional timezone short name (like "CST" or "CEST")
.optionalStart().appendZoneText(TextStyle.SHORT, set).optionalEnd()
// optional GMT offset (like "GMT+02:00")
.optionalStart().appendPattern("OOOO").optionalEnd()
// year
.appendPattern(" yyyy")
// create formatter (using English locale to make sure it parses weekday and month names correctly)
.toFormatter(Locale.US);
To parse Tue Jun 20 14:53:08 CEST 2017, just use the formatter:
ZonedDateTime z1 = ZonedDateTime.parse("Tue Jun 20 14:53:08 CEST 2017", fmt);
System.out.println(z1);
The output is:
2017-06-20T14:53:08+02:00[Europe/Berlin]
Note that CEST was mapped to Europe/Berlin, according to the set we created.
To parse Tue Jun 20 13:40:37 GMT+02:00 2017, we can use the same formatter. But GMT+02:00 can be in a lot of different regions, so the API can't map it to a single timezone. To convert it to the correct timezone, I need to use withZoneSameInstant() method:
// parse with UTC offset
ZonedDateTime z2 = ZonedDateTime.parse("Tue Jun 20 13:40:37 GMT+02:00 2017", fmt)
// convert to Berlin timezone
.withZoneSameInstant(ZoneId.of("Europe/Berlin"));
System.out.println(z2);
The output is:
2017-06-20T13:40:37+02:00[Europe/Berlin]
PS: the first case (z1) works in Java 8, but in ThreeTen Backport it's not setting the timezone to Berlin. To fix it, just call .withZoneSameInstant(ZoneId.of("Europe/Berlin")) as we did with z2.
If you still need to use java.util.Date, you can convert from and to the new API.
In java.time, new methods were added to Date class:
// convert ZonedDateTime to Date
Date date = Date.from(z1.toInstant());
// convert back to ZonedDateTime (using Berlin timezone)
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Europe/Berlin"));
In ThreeTen backport (and Android), you can use the org.threeten.bp.DateTimeUtils class:
// convert ZonedDateTime to Date
Date date = DateTimeUtils.toDate(z1.toInstant());
// convert back to ZonedDateTime (using Berlin timezone)
ZonedDateTime z = DateTimeUtils.toInstant(date).atZone(ZoneId.of("Europe/Berlin"));
java.time
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*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Do not use a fixed text for the timezone:
Do not use a fixed text (e.g. 'GMT') for the timezone as you have done because that approach may fail for other locales.
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) {
// Test
System.out.println(parse("Tue Jun 20 14:53:08 CEST 2017"));
System.out.println(parse("Tue Jun 20 13:40:37 GMT+02:00 2017"));
}
static ZonedDateTime parse(String strDateTime) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM d H:m:s z u", Locale.ENGLISH);
return ZonedDateTime.parse(strDateTime, dtf);
}
}
Output:
2017-06-20T14:53:08+02:00[Europe/Paris]
2017-06-20T13:40:37+02:00[GMT+02:00]
ONLINE DEMO
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.

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.

How to convert a date in this format (Tue Jul 13 00:00:00 CEST 2010) to a Java Date (The string comes from an alfresco property)

i'm managing a date that comes from an Alfresco Properties and is in the specified (Tue Jul 13 00:00:00 CEST 2010) and i need to convert it to a Java date...i've looked around and found millions of posts for various string to date conversion form and also this page and so i tried something like this:
private static final DateFormat alfrescoDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
Date dataRispostaDate = alfrescoDateFormat.parse(dataRisposta);
But it throws an exception.(The exception is (SSollevata un'eccezione durante la gestione della data: java.text.ParseException: Unparseable date: "Tue Jul 13 00:00:00 CEST 2011").
I post the complete code:
try {
QName currDocTypeQName = (QName) nodeService.getType(doc);
log.error("QName:["+currDocTypeQName.toString()+"]");
if (currDocTypeQName != null) {
String codAtto = AlfrescoConstants.getCodAttoFromQName(currDocTypeQName.toString());
log.error("codAtto:["+codAtto+"]");
if (codAtto.equals(AlfrescoConstants.COD_IQT)){
List<ChildAssociationRef> risposteAssociate = nodeService.getChildAssocs(doc, AlfrescoConstants.QN_RISPOSTEASSOCIATE, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef childAssocRef : risposteAssociate) {
// Vado a prendere il nodo
NodeRef risposta = childAssocRef.getChildRef();
String dataRisposta = (nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA)).toString();
log.error("dataRisposta:["+dataRisposta+"]");
if (!dataRisposta.isEmpty()){
try {
Date dataDa = dmyFormat.parse(req.getParameter("dataDa"));
log.error("dataDa:["+dataDa.toString()+"]");
Date dataA = dmyFormat.parse(req.getParameter("dataA"));
log.error("dataA:["+dataA.toString()+"]");
Date dataRispostaDate = alfrescoDateFormat.parse(dataRisposta);
log.error("dataRispostaDate:["+dataRispostaDate.toString()+"]");
if (dataRispostaDate.after(dataDa) && dataRispostaDate.before(dataA)){
results.add(doc);
log.error("La data risposta è compresa tra le date specificate");
}else{
log.error("La data risposta non è compresa tra le date specificate");
}
} catch (ParseException e) {
log.error("Sollevata un'eccezione durante la gestione della data: " + e);
throw new RuntimeException("Formato data non valido");
}
}else{
log.error("La data risposta non è specificata");
}
}
}else{
results.add(doc);
}
}
} catch (Exception e) {
log.error("Sollevata un'eccezione durante la gestione del codice atto nel webscript nicola: " + e);
}
Anyone can help?
Basically your problem is that you are using a SimpleDateFormat(String pattern) constructor, where javadoc says:
Constructs a SimpleDateFormat using
the given pattern and the default date
format symbols for the default locale.
And if you try using this code:
DateFormat osLocalizedDateFormat = new SimpleDateFormat("MMMM EEEE");
System.out.println(osLocalizedDateFormat.format(new Date()))
you will notice that it prints you month and day of the week titles based on your locale.
Solution to your problem is to override default Date locale using SimpleDateFormat(String pattern, Locale locale) constructor:
DateFormat dateFormat = new SimpleDateFormat(
"EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
dateFormat.parse("Tue Jul 13 00:00:00 CEST 2011");
System.out.println(dateFormat.format(new Date()));
tl;dr
ZonedDateTime.parse( // Produce a `java.time.ZonedDateTime` object.
"Wed Jul 13 00:00:00 CEST 2011" , // Corrected `Tue` to `Wed`.
DateTimeFormatter.ofPattern( "EEE MMM d HH:mm:ss zzz uuuu" , Locale.US )
)
2011-07-13T00:00+02:00[Europe/Paris]
Bad data: Wed vs Tue
You input string Tue Jul 13 00:00:00 CEST 2011 is invalid. July 13 of 2011 was a Wednesday, not a Tuesday.
String input = "Wed Jul 13 00:00:00 CEST 2011" ; // Corrected `Tue` to `Wed`.
java.time
The modern approach uses the java.time classes rather than the troublesome old legacy date-time classes seen in other Answers.
Define a formatting pattern to match your input string. Notice the Locale, which defines the human language to be used in parsing name of month and name of day-of-week.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE MMM d HH:mm:ss zzz uuuu" , Locale.US );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
zdt.toString(): 2011-07-13T00:00+02:00[Europe/Paris]
Time zone
Your CEST is a pseudo-zone, not a true time zone. Never use these. They are not standardized, and are not even unique(!).
The ZonedDateTime class will make a valiant effort at guessing the intention behind such a 3-4 character pseudo-zone. Your CEST happened to work here, interpreted as Europe/Paris time zone. But you cannot rely on the guess being 100% successful. Instead, avoid such pseudo-zones entirely.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland.
ZoneId z = ZoneId.of( "Europe/Paris" ); // https://time.is/Paris
LocalDate today = LocalDate.now( z ); // Current date varies around the globe by zone.
ISO 8601
Your input string’s format is terrible. When serializing date-time values as text, use only the standard ISO 8601 formats.
The ZonedDateTime class wisely extends the standard format by appending the name of the time zone in square brackets as seen in examples above.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and 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 (JSR 310) classes.
For earlier Android, 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.
Based on your comments, I believe that your property is actually of type d:date or d:datetime. If so, the property will already be coming back from Alfresco as a java Date object. So, all you'd need to do is:
NodeRef risposta = childAssocRef.getChildRef();
Date dataRisposta = (Date)nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA);
The problem is that CEST is not a timezone Java supports. You can use "CST".
The Javadoc for TimeZone notes:
Three-letter time zone IDs
For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such as "PST", "CTT", "AST") are also supported. However, their use is deprecated because the same abbreviation is often used for multiple time zones (for example, "CST" could be U.S. "Central Standard Time" and "China Standard Time"), and the Java platform can then only recognize one of them.
For three/four letter timezone support I suggest you try JodaTime which may do a better job.
String dataRisposta = "Tue Jul 13 00:00:00 CST 2010";
Date dataRispostaDate = alfrescoDateFormat.parse(dataRisposta);
System.out.println(dataRispostaDate);
prints
Tue Jul 13 07:00:00 BST 2010
String[] ids = TimeZone.getAvailableIDs();
Arrays.sort(ids);
for (String id : ids) {
System.out.println(id);
}
prints
...
CAT
CET
CNT
CST
CST6CDT
CTT
...
Try this function I had the same issue.
public String getMyDate(String myDate, String requiredFormat, String mycurrentFormat) {
DateFormat dateFormat = new SimpleDateFormat(returnFormat);
Date date = null;
String returnValue = "";
try {
date = new SimpleDateFormat(myFormat, Locale.ENGLISH).parse(myDate);
returnValue = dateFormat.format(date);
} catch (ParseException e) {
returnValue = myDate;
}
return returnValue;
}
Example:
Wed May 06 13:01:29 EDT 2020 i.e "EEE MMM dd HH:mm:ss zzz yyyy" is mycurrentFormat
4.May.2020 i.e. "d.MMM.yyyy" is my requiredFormat
Date date = new Date();
getMyDate(date.toString(), "d.MMM.yyyy", "EEE MMM dd HH:mm:ss zzz yyyy")

Convert String to Calendar Object in Java

I am new to Java, usually work with PHP.
I am trying to convert this string:
Mon Mar 14 16:02:37 GMT 2011
Into a Calendar Object so that I can easily pull the Year and Month like this:
String yearAndMonth = cal.get(Calendar.YEAR)+cal.get(Calendar.MONTH);
Would it be a bad idea to parse it manually? Using a substring method?
Any advice would help thanks!
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
cal.setTime(sdf.parse("Mon Mar 14 16:02:37 GMT 2011"));// all done
note: set Locale according to your environment/requirement
See Also
Javadoc
tl;dr
The modern approach uses the java.time classes.
YearMonth.from(
ZonedDateTime.parse(
"Mon Mar 14 16:02:37 GMT 2011" ,
DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" )
)
).toString()
2011-03
Avoid legacy date-time classes
The modern way is with java.time classes. The old date-time classes such as Calendar have proven to be poorly-designed, confusing, and troublesome.
Define a custom formatter to match your string input.
String input = "Mon Mar 14 16:02:37 GMT 2011";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" );
Parse as a ZonedDateTime.
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
You are interested in the year and month. The java.time classes include YearMonth class for that purpose.
YearMonth ym = YearMonth.from( zdt );
You can interrogate for the year and month numbers if needed.
int year = ym.getYear();
int month = ym.getMonthValue();
But the toString method generates a string in standard ISO 8601 format.
String output = ym.toString();
Put this all together.
String input = "Mon Mar 14 16:02:37 GMT 2011";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
YearMonth ym = YearMonth.from( zdt );
int year = ym.getYear();
int month = ym.getMonthValue();
Dump to console.
System.out.println( "input: " + input );
System.out.println( "zdt: " + zdt );
System.out.println( "ym: " + ym );
input: Mon Mar 14 16:02:37 GMT 2011
zdt: 2011-03-14T16:02:37Z[GMT]
ym: 2011-03
Live code
See this code running in IdeOne.com.
Conversion
If you must have a Calendar object, you can convert to a GregorianCalendar using new methods added to the old classes.
GregorianCalendar gc = GregorianCalendar.from( zdt );
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. Hibernate 5 & JPA 2.2 support java.time.
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 brought 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 (26+) bundle implementations of the java.time classes.
For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
Well, I think it would be a bad idea to replicate the code which is already present in classes like SimpleDateFormat.
On the other hand, personally I'd suggest avoiding Calendar and Date entirely if you can, and using Joda Time instead, as a far better designed date and time API. For example, you need to be aware that SimpleDateFormat is not thread-safe, so you either need thread-locals, synchronization, or a new instance each time you use it. Joda parsers and formatters are thread-safe.
No new Calendar needs to be created, SimpleDateFormat already uses a Calendar underneath.
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.EN_US);
Date date = sdf.parse("Mon Mar 14 16:02:37 GMT 2011"));// all done
Calendar cal = sdf.getCalendar();
(I can't comment yet, that's why I created a new answer)
SimpleDateFormat is great, just note that HH is different from hh when working with hours. HH will return 24 hour based hours and hh will return 12 hour based hours.
For example, the following will return 12 hour time:
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa");
While this will return 24 hour time:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
Parse a time with timezone, Z in pattern is for time zone
String aTime = "2017-10-25T11:39:00+09:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
try {
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(aTime));
Log.i(TAG, "time = " + cal.getTimeInMillis());
} catch (ParseException e) {
e.printStackTrace();
}
Output: it will return the UTC time
1508899140000
If we don't set the time zone in pattern like yyyy-MM-dd'T'HH:mm:ss. SimpleDateFormat will use the time zone which have set in Setting
Yes it would be bad practice to parse it yourself. Take a look at SimpleDateFormat, it will turn the String into a Date and you can set the Date into a Calendar instance.
Simple method:
public Calendar stringToCalendar(String date, String pattern) throws ParseException {
String DEFAULT_LOCALE_NAME = "pt";
String DEFAULT_COUNTRY = "BR";
Locale DEFAULT_LOCALE = new Locale(DEFAULT_LOCALE_NAME, DEFAULT_COUNTRY);
SimpleDateFormat format = new SimpleDateFormat(pattern, LocaleUtils.DEFAULT_LOCALE);
Date d = format.parse(date);
Calendar c = getCalendar();
c.setTime(d);
return c;
}

Categories