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.
Related
I had two edit text for user to enter time (24 hours format).
How could i get those times from Edittext and deduct 5 hours and 30 minutes from user selected time.
Reason for deducting time : Converting IST to UTC timezone.
My final output should be like - HH:MM:SS:Milleseconds (Ex : 18:25:30:245635).
Thanks in advance.
java.time
ZoneId zone = ZoneId.of("Asia/Kolkata");
String timeString = "18:25:30.245635";
LocalTime time = LocalTime.parse(timeString);
LocalTime utcTime = LocalDate.now(zone) // Today
.atTime(time) // Today at the time in question
.atZone(zone) // Date and time in IST
.toOffsetDateTime() // Convert to OffsetDateTime for the next step
.withOffsetSameInstant(ZoneOffset.UTC) // Convert to UTC
.toLocalTime(); // Extract only the time of day
System.out.println("UTC time: " + utcTime);
Output is:
UTC time: 12:55:30.245635
I have assumed today’s date. Please check if this assumption is right for you. While the UTC offset for Asia/Kolkata hasn’t changed much recently, other time zones change their offset twice a year.
I changed your time format to have a period (point) rather than a colon between the seconds and fraction of second as is customary. If you do require a colon there, you need a DateTimeFormatter for parsing.
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) 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.
Wikipedia article: ISO 8601
In Android...I am expecting 3:12 pm as time out put of the following code but I get 4:12 pm. Whats the correct way to parse this date time format.
String dt = "2018-09-02T19:12:00-0400";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
try {
Date date = dateFormat.parse(dt);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
Time zone
It’s best to specify explicitly in which time zone you want your output:
DateTimeFormatter inputFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX");
DateTimeFormatter displayFormatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.ENGLISH);
ZoneId displayZone = ZoneId.of("Pacific/Pitcairn");
String dt = "2018-09-02T19:12:00-0400";
OffsetDateTime dateTime = OffsetDateTime.parse(dt, inputFormatter);
String displayDateTime = dateTime.atZoneSameInstant(displayZone)
.format(displayFormatter);
System.out.println(displayDateTime);
This prints:
September 2, 2018 at 3:12:00 PM PST
I have used Pacific/Pitcairn time zone in my code, but you know better which time zone you want.
I am also using java.time, the modern Java date and time API. The date-time classes you are using, SimpleDateFormat and Date, are considered long outdated, and java.time is so much nicer to work with.
What went wrong in your code?
Your way of parsing your date string is correct and produces the correct Date.
When printing the Date, you are implicitly calling toString. The outdated Date class has a peculiar and confusing toString method: it grabs the JVM’s time zone setting and uses it for producing the string. So depending on your default time zone, you can get any hour of day in the output. So it seems your JVM’s time zone setting didn’t correspond to what you had expected.
Since you expected 3:12 PM from your input of 19:12:00-0400, I take it that you want a time zone that is at offset -08:00 from UTC in September. If for example your default time zone was America/Los_Angeles, the standard time of which is at -08:00, you would get Sun Sep 02 16:12:00 PDT 2018 because summer time (daylight saving time) is in effect in California in September, so the offset is -07:00.
Relying on your JVM’s default time zone is always fragile since the setting may be changed at any time by other parts of your program or by other programs running in the same JVM.
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.
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 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);
Anybody know how to parse time (hour, minute and AM/PM) from a string that looks like "01:20" -> 1:20AM and "21:20" -> 9:20PM? Most solutions out there seem to assume or require a Date or Calendar object.
My input time is actually coming from a TimePickerDialog (specifically, this MaterialDateTimePicker implementation, so I receive only the hourOfDay, minute and seconds (integers).
I want to be able to format the time that the user picked in a friendly way, i.e 12:30PM, 02:15AM, etc.
I am trying to use Joda Time:
fun formattedTime(timeStr: String): String {
// Get time from date
val timeFormatter = DateTimeFormat.forPattern("h:mm a")
val displayTime = timeFormatter.parseLocalTime(timeStr)
return displayTime.toString()
}
but I get this error with an input string such as "1:20":
java.lang.IllegalArgumentException: Invalid format: "1:20" is too short
I have also looked into SimpleDateFormat but it seems to require a full date-time string such as in this related question
As #ole-v-v pointed out, SimpleDateFormat has seen better days - so today you can make use of the java.time package to do the job:
java.time.format.DateTimeFormatter target2 =
java.time.format.DateTimeFormatter.ofPattern("h:mm a");
java.time.format.DateTimeFormatter source2 =
java.time.format.DateTimeFormatter.ofPattern("HH:mm");
System.out.println("01:30 -> " + target2.format(source2.parse("01:30")));
System.out.println("21:20 -> " + target2.format(source2.parse("21:20")));
Yields the result of
01:30 -> 1:30 AM
21:20 -> 9:20 PM
as expected.
In Joda-Time you would code it as #meno-hochschild pointed out in his answer below.
Using SimpleDateFormat it will look like this:
SimpleDateFormat target = new SimpleDateFormat("h:mm a");
SimpleDateFormat source = new SimpleDateFormat("HH:mm");
System.out.println("01:30 -> " + target.format(source.parse("01:30")));
System.out.println("21:20 -> " + target.format(source.parse("21:20")));
This will parse from 24h times to 12 hours display
01:30 -> 1:30 AM
21:20 -> 9:20 PM
It all depends on the format for the hours - for parsing you'll want 24h hours (format HH), for output you want 12 hours plus am / pm - format is h.
If you want 01:30 to be PM you'll have to add that to the string to be parsed somehow:
System.out.println("01:30 pm-> " + target.format(target.parse("01:30 pm")));
resulting in
01:30 pm-> 1:30 PM
The accepted answer is correct. However, I am astonished to see the old classes like SimpleDateFormat although the OP has explicitly first desired a Joda answer (see the tags of the question). So I post here the Joda answer as supplement:
DateTimeFormatter target = DateTimeFormat.forPattern("h:mm a").withLocale(Locale.ENGLISH);
DateTimeFormatter source = DateTimeFormat.forPattern("HH:mm");
System.out.println("01:30 -> " + target.print(source.parseLocalTime("01:30")));
System.out.println("21:20 -> " + target.print(source.parseLocalTime("21:20")));
01:30 -> 1:30 AM
21:20 -> 9:20 PM
I advise not to mix two different time libraries (the OP obviously uses Joda-Time-Android).
Your two good options are Joda-Time and java.time.
Since you receive hourOfDay, minute and seconds as integers from the time picker, you don’t need to do any parsing.
java.time
DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
.withLocale(Locale.US);
LocalTime time = LocalTime.of(hourOfDay, minute, second);
String displayTime = time.format(timeFormatter);
System.out.println(displayTime);
This prints the time like this:
11:45 PM
Rather than an explicit format pattern string I am relying on the built-in localized format for the US locale. It has put a space between the minutes and PM (or AM). I believe your users will be happy about that. If not, you will need to use DateTimeFormatter.ofPattern("h:mma", Locale.US) instead.
Joda-Time
If you are already using Joda-Time and don’t have a reason for changing at this point, sticking to it is reasonable. You may use the LocalTime(int hourOfDay, int minuteOfHour, int secondOfMinute) constructor. Then proceed as in Meno Hochschild’s answer. It’s a good and knowledgeable answer.
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).
(Quoted from the Joda-Time homepage)
Stay away from SimpleDateFormat
Stay far away from the SimpleDateFormat class. It can be made to work for the job, but it 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.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.