I have obtained a string from an API in form of 2017-04-23T19:47:39+00:00
How do i convert it into date of format "2017-04-23T19:47:39-0000"?
I tried the following but it gave ParseException
String created_at_string = "2017-04-23T19:47:39+00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date created_at = sdf.parse(created_at_string);
Exception:
06-22 18:18:32.517 10396-10396/com.harit.abs W/System.err: java.text.ParseException: Unparseable date: ""2018-04-29T10:55:37+00:00""
at java.text.DateFormat.parse(DateFormat.java:358)
at com.harit.abs.Sync_Activity.bu(Sync_Activity.java:169)
at com.harit.abs.Sync_Activity$2.onCompleted(Sync_Activity.java:118)
at com.harit.abs.Sync_Activity$2.onCompleted(Sync_Activity.java:87)
at com.koushikdutta.async.future.SimpleFuture.handleCallbackUnlocked(SimpleFuture.java:107)
at com.koushikdutta.async.future.SimpleFuture.setComplete(SimpleFuture.java:141)
at com.koushikdutta.async.future.SimpleFuture.setComplete(SimpleFuture.java:128)
at com.koushikdutta.ion.IonRequestBuilder$1.run(IonRequestBuilder.java:246)
at com.koushikdutta.async.AsyncServer$RunnableWrapper.run(AsyncServer.java:60)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
Tried what is given in SimpleDateFormat with TimeZone
Still getting the same parse Exception
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
String created_at_string = "2017-04-23T19:47:39+00:00";
Date created_at = sdf.parse(created_at_string);
You don’t need to
The conversion you are asking about could easily be superfluous. You are asking for a string like 2017-04-23T19:47:39-0000. This string is in ISO 8601 format, the international standard format. So depending on your exact situation I would expect a string in ISO 8601 to be fine for you. The string you already got, 2017-04-23T19:47:39+00:00 is in ISO 8601 too! The standard allows for some variations, and one of them is that the colon in the offset is optional. So the first thing I think that you should do is to pass on the string you get and see if that works. In case it doesn’t, read on.
java.time
Your desired conversion goes so smoothly with java.time the modern Java date and time API:
DateTimeFormatter formatterWithoutColon
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssxx");
String createdAtString = "2017-04-23T19:47:39+00:00";
OffsetDateTime dateTime = OffsetDateTime.parse(createdAtString);
String inDesiredFormat = dateTime.format(formatterWithoutColon);
System.out.println(inDesiredFormat);
This prints the desired:
2017-04-23T19:47:39+0000
Please note that we didn’t even need a formatter for parsing the string. OffsetDateTime and many other classes of java.time parse ISO 8601 as their default. Since our requirements for the result are a bit more precise, we use a formatter here. xx gives us the offset without colon, for example +0000.
The Date class that you used is long outdated. So is SimpleDateFormat, and it’s notoriously troublesome too. I suggest you avoid those classes.
Question: Can I use java.time on Android?
Yes, java.time works nicely on 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, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
The hack
The change you require is very simple, you just want a colon removed. So another, not so nice, but basic and simple solution that doesn’t require ThreeTenABP is a regular expression:
String inDesiredFormat = createdAtString.replaceFirst("([+-]\\d{2}):(\\d{2})$", "$1$2");
This gives the same result as above.
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.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
Possibly you could try to set the locale,
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
Related
I'm writing an app for android. On the start of it I create a Calendar, filling such containers as YEAR, MONTH, DAY_OF_MONTH, ERA and time zone as GMT.
I get something like this
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=java.util.SimpleTimeZone[id=GMT,offset=0,dstSavings=3600000,useDaylight=false,startYear=0,startMode=0,startMonth=0,startDay=0,startDayOfWeek=0,startTime=0,startTimeMode=0,endMode=0,endMonth=0,endDay=0,endDayOfWeek=0,endTime=0,endTimeMode=0],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2021,MONTH=3,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=14,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
Later on I need to get a string like "14-04-2021", so I create a Date variable using getTimeInMillies for the Calendar before. All the fields of it become filled with zeros.
After parsing a JSON, I need to create a map with Calendar keys. It looks like this.
String key = keys.next();
Date d = dateFormat.parse(key);
String rate = String.valueOf(rates.getJsonObject(key).get(get_curr_inf(get_curr_to_r())));
Double rate_ = Double.parseDouble(rate);
Calendar cal = new GregorianCalendar();
cal.setTime(d);
Calendar tmp = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
tmp.setTimeZone(TimeZone.getTimeZone("GMT"));
tmp.set(Calendar.ERA, 1);
long f = tmp.getTimeInMillis();
data.put(tmp, rate_);
I do it in such a strange way as it needs to be exactly similar to the previous Calendar, cause i parse map using it.
Is there any way to make it look better?
Never use Calendar. That terrible class was supplanted years ago by the modern java.time classes.
For a date-only value without time-of-day and without time zone, use LocalDate.
On the start of it I create a Calendar, filling such containers as YEAR, MONTH, DAY_OF_MONTH, ERA and time zone as GMT.
LocalDate ld = LocalDate.of( 2021, Month.APRIL , 14 ) ;
I need to get a string like "14-04-2021"
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu" ) ;
String output = ld.format( f ) ;
I need to create a map with Calendar keys
Map< LocalDate , … > map = new … ;
map.put( ld , … ) ;
The java.time classes are built into Android 26 and later. The latest Android tooling brings much of that functionality to earlier Android by way of API desugaring.
java.time
The first answer is to change your map to use LocalDate as key instead of Calendar. Two LocalDate objects denoting the same day will always be equal and produce the same hash code, so are ideal as map keys. Follow the answer by Basil Bourque.
The second answer, if for some reason you cannot change the type of the map keys, you can still produce an old-fashioned Calendar object more nicely using java.time, the modern Java date and time API.
String key = "14-04-2021";
LocalDate date = LocalDate.parse(key, DATE_FORMATTER);
ZonedDateTime zdt = date.atStartOfDay(ZoneOffset.UTC);
GregorianCalendar tmpCal = GregorianCalendar.from(zdt);
System.out.println(tmpCal);
I used this formatter:
private static final DateTimeFormatter DATE_FORMATTER
= DateTimeFormatter.ofPattern("dd-MM-uuuu");
And output is:
java.util.GregorianCalendar[time=1618358400000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2021,MONTH=3,WEEK_OF_YEAR=15,WEEK_OF_MONTH=3,DAY_OF_MONTH=14,DAY_OF_YEAR=104,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]
It is not completely equal to the result you had, so will not be compatible with Calendar objects produced your old way. One difference is that all fields are set. java.time cannot produce a Calendar with only selected fields set as you had before. The other difference could be eliminated: my time zone is UTC instead of GMT. In practice they are the same. To get GMT, use ZoneId.of("GMT") instead of ZoneOffset.UTC.
So if you can enforce that now all map keys are produced in the new way, I should say that you are set.
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.
I get the datetime content in the below string format with offset time value from the source system.
2019-02-16T10:00:00+08:00
Where i want to convert that into local date time using the offset value.I tried the below, but not getting the expected result.
DateTime date = new DateTime("2019-02-16T10:00:00+08:00");
-->output == 2019-02-16T02:00:00.000Z (the hour is decreased instead of increasing)
DateTime date = new DateTime("2019-02-16T10:00:00-08:00");
-->output == 2019-02-16T18:00:00.000Z (the hour is increased instead of decreasing).
is there any simple way to the expected output?
Note: I am using Java 1.7
What you are doing is correct. To get the time in your local time zone:
DateTime date = new DateTime("2019-02-16T10:00:00+08:00");
DateTime dateTimeInLocalTimeZone = date.withZone(DateTimeZone.getDefault());
System.out.println(dateTimeInLocalTimeZone);
On my computer in Europe/Copenhagen time zone I got
2019-02-16T03:00:00.000+01:00
As has been said in the comments, +08:00 is the offset that has already been added compared to UTC time. So your string denoted the same point in time as 2019-02-16T02:00:00+00:00. It may also be written as 2019-02-16T02:00:00Z since Z (pronounced “Zulu”) means UTC.
java.time and ThreeTen Backport
If you are not already tied to Joda-Time, you may prefer to use java.time, the modern Java date and time API. The code is similar:
OffsetDateTime sourceDateTime = OffsetDateTime.parse("2019-02-16T10:00:00+08:00");
ZonedDateTime dateTimeInLocalTimeZone = sourceDateTime.atZoneSameInstant(ZoneId.systemDefault());
2019-02-16T03:00+01:00[Europe/Copenhagen]
Question: Can I use java.time on Java 1.7?
Note: I am using Java 1.7
No big problem, java.time just requires at least Java 6. I have run the above code on jdk1.7.0_79.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In 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 use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And 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).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Another way to do that :
String dt = "2019-02-16T10:00:00+08:00";
ZonedDateTime zd = ZonedDateTime.parse("2019-02-16T10:00:00+08:00");
System.out.println(zd.toLocalDateTime().plusSeconds(zd.getOffset().getTotalSeconds()));
Output
2019-02-16T18:00
I've taken all of the answers given on SOF and other websites and tried to do this:
String fromDateTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sssX").format(new DateTime().plusMonths(-6));
But I'm being given the exception:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot format given Object as a Date
What am I doing wrong?
java.time
String fromDateTime = OffsetDateTime.now(ZoneId.systemDefault()).minusMonths(6).toString();
System.out.println(fromDateTime);
Output when running on my computer just now:
2018-08-04T12:45:34.087966+01:00
java.time is the modern Java date and time API and has effectively replaced Joda-Time. From the home page:
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time (JSR-310).
In the code I am taking advantage of the fact that the java.time classes’ toString methods produce ISO 8601 format, the format you were asking for. I find it unlikely that the extra decimals on the seconds will pose any problem since thay are allowed within the standard.
Joda-Time
String fromDateTime = new DateTime().minusMonths(6).toString();
Example output:
2018-08-04T12:50:36.071+02:00
new DateTime() only has millisecond precision. You will always get exactly 3 decimals on the seconds.
I gotta use old java libraries, cause I work for a company that uses java version < 8
java.time works nicely on Java 6 and 7 too, and all things being equal I recommend it over Joda-Time. Only if forced to use Java 5, Joda-Time is no doubt the good choice.
In Java 8 and later and on newer Android devices (from API level 26) java.time comes built-in.
In 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 use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
What went wrong in your code?
Your code can be compiled without signs of errors, but issues a java.lang.IllegalArgumentException: Cannot format given Object as a Date when run. This is because a SimpleDateFormat cannot format a Joda-Time DateTime object. We would of course have expected this to be reported on compile time. But in addition to SimpleDateFormat.format(Date) there is also an overridden format(Object) inherited from Format. It works for formatting either a Date or a Number (for milliseconds since the epoch). This method is the one that the compiler chooses when you pass a DateTime. Which is why there is no compile-time error message.
Tip: When you don’t immediately understand an error message, paste it into your search engine. It will very often lead you to an explanation and a solution. Also in this case.
Links
Joda-Time home page
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).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
Sister question: Java : Cannot format given Object as a Date.
Try the following:
String fromDateTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sssX").format(new DateTime().minusMonths(6).toDate());
You have to convert the DateTime to a Date before formatting, using the toDate() method will do the job.
API for toDate() and API for minusMonths, I would recommend to you check the API for new methods
This question already has answers here:
Java - Unparseable date
(3 answers)
Getting error java.text.ParseException: Unparseable date: (at offset 0) even if the Simple date format and string value are identical
(4 answers)
Closed 4 years ago.
I am trying to parse the following date/time:
Wed, 29 Aug 2018 12:56:00 +0200
Currently, I am using the following code which works on my Android emulator but on my actual phone I get a "java.text.ParseException: Unparseable date"
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
this.pubDate = sdf.parse(s_pubDate);
You need to explicitly set the formatter locale, otherwise it would try to pars it based on phone locale and that may cause an error. I think that the cause in your case.
Your emulated device has one locale, while your phone has the one, that can't pars date in such format.
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z",
**YOUR DESIRED LOCALE**);
java.time
String dateTimeString = "Wed, 29 Aug 2018 12:56:00 +0200";
OffsetDateTime dateTime = OffsetDateTime.parse(
dateTimeString, DateTimeFormatter.RFC_1123_DATE_TIME);
System.out.println(dateTime);
Output from this snippet is:
2018-08-29T12:56+02:00
The format of the string you want to parse is RFC 1123. This format is built into Java, so spares you the trouble of building your own formatter for parsing. Furthermore RFC 1123 is always in English, so there is no risk that your phone’s default locale (or any other locale) interferes.
I am using java.time, the modern Java date and time API. The SimpleDateFormat that you tried to use is not only long outdated, it is also notoriously troublesome.
Question: Can I use java.time on Android?
Yes, java.time works nicely on 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, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And 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).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
I've got a SimpleDateFormat to parse a String into a Date:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ");
When I'm parsing this:
format.parse("2011-08-29T12:44:00+0200");
The result will be, when using Date.toLocaleString:
29 aug. 2011 00:44:00
This should be ofcourse:
29 aug. 2011 12:44:00
And when I'm parsing this:
format.parse("2011-08-29T13:44:00+0200");
Then the result is as expected:
29 aug. 2011 13:44:00
How can I fix this?
Use HH instead of hh for the hours pattern:
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
h Hour in am/pm (1-12) Number 12
java.time through desugaring
I suggest that you use java.time, the modern Java date and time API, for your date and time work.
Your string is in ISO 8601 format. Define a formatter for it:
private static final DateTimeFormatter ISO_FORMATTER
= new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffset("+HHMM", "Z")
.toFormatter(Locale.ROOT);
It could have been shorter with a format pattern string, but I prefer to reuse the built-in ISO_LOCAL_DATE_TIME, which already handles ISO 8601. As your question testifies, writing a format pattern string is error-prone. I have also specified that an offset of zero from UTC should be accepted as Z in accordance with ISO 8601 (the parser will accept +0000 too).
Parse like this:
String isoString = "2011-08-29T12:44:00+0200";
OffsetDateTime dateTime = OffsetDateTime.parse(isoString, ISO_FORMATTER);
System.out.println(dateTime);
Output is:
2011-08-29T12:44+02:00
To obtain a string formatted for the user’s locale use a second formatter:
private static final DateTimeFormatter LOCALE_FORMATTER
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
We still need not write any format pattern string. Format like this:
String localeString = dateTime.format(LOCALE_FORMATTER);
System.out.println(localeString);
Output is exactly what it should be. I ran in nl_NL locale and got:
29 aug. 2011 12:44:00
Please skip the next section.
What if I need an old-fashioned java.util.Date?
No one should use the Date class anymore. Only if you indispensably need a Date for a legacy API that you cannot afford to upgrade to java.time right now, convert:
Date oldfashionedDate = Date.from(dateTime.toInstant());
System.out.println(oldfashionedDate);
Funnily output will be time zone dependent. In my time zone I got:
Mon Aug 29 12:44:00 CEST 2011
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.
Wikipedia article: ISO 8601
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.