Parse date from string on Android Lollipop - android

I have a date string like 2021-02-20 12:24:10 and I need to parse it to Date. I have the solution, which works on Nougat (API 24) and higher, but I need need the solution for Lollipop (API 21). The solution for Nougat is below
val parser = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val entryDate: Date = parser.parse(ticketResponse.entryDate)
I tried to use DateFormat, but I get ParseException when I try to parse my date
val entryDate: Date = DateFormat.getInstance().parse(ticketResponse.entryDate)
I understand it happens because my input string is not a standard representation of date, but I cannot easy change it, I get this date from server. I also didn't find way to set pattern for input date like for SimpleDateFormat.
I am surprised that where is no answer here in some old questions, all answers recommend to use SimpleDateFormat. Of course I can split date with dividers, but I would like to use not so bold approach.

if you haven't noticed there are two SimpleDateFormat classes with a different package: java.text.SimpleDateFormat; and android.icu.text.SimpleDateFormat;
please try to use the first one it is added in api level 1 chek this link :
https://www.datetimeformatter.com/how-to-format-date-time-in-kotlin/

Related

org.threeten.bp zonedDateTime.parse does not work [duplicate]

I recently moved to Java 8 to, hopefully, deal with local and zoned times more easily.
However, I'm facing an, in my opinion, simple problem when parsing a simple date.
public static ZonedDateTime convertirAFecha(String fecha) throws Exception {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
ConstantesFechas.FORMATO_DIA).withZone(
obtenerZonaHorariaServidor());
ZonedDateTime resultado = ZonedDateTime.parse(fecha, formatter);
return resultado;
}
In my case:
fecha is '15/06/2014'
ConstantesFechas.FORMATO_DIA is 'dd/MM/yyyy'
obtenerZonaHorariaServidor returns ZoneId.systemDefault()
So, this is a simple example. However, the parse throws this exception:
java.time.format.DateTimeParseException: Text '15/06/2014' could not
be parsed: Unable to obtain ZonedDateTime from TemporalAccessor:
{},ISO resolved to 2014-06-15 of type java.time.format.Parsed
Any tips? I've been trying different combinations of parsing and using TemporalAccesor, but without any luck so far.
This does not work because your input (and your Formatter) do not have time zone information. A simple way is to parse your date as a LocalDate first (without time or time zone information) then create a ZonedDateTime:
public static ZonedDateTime convertirAFecha(String fecha) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date = LocalDate.parse(fecha, formatter);
ZonedDateTime resultado = date.atStartOfDay(ZoneId.systemDefault());
return resultado;
}
This is a bug, see JDK-bug-log. According to that information the problem was solved for Java 9 and Java 8u20. Try to download the latest Java 8 - version. Today on 2014-05-12: There is an early access release 8u20 available.
UPDATE:
Personally I think, since you only have and expect "dd/MM/yyyy" as pattern you should use LocalDate as your primary type as #assylias has already proposed. Regarding your context, it is almost sure a design failure to use ZonedDateTime. What do you want to do with objects of this type? I can only think of specialized timezone calculations as use-case. And you cannot even directly store these ZonedDateTime-objects in a database, so this type is far less useful than many people believe.
What I described as your use-case problem is indeed a new aspect introduced with Java-8 compared with the old GregorianCalendar-class (which is an all-in-one-type). Users have to start thinking about choosing the proper temporal type for their problems and use-cases.
In simple words, the line
ZonedDateTime.parse('2014-04-23', DateTimeFormatter.ISO_OFFSET_DATE_TIME)
throws an exception:
Text '2014-04-23' could not be parsed at index 10
java.time.format.DateTimeParseException: Text '2014-04-23' could not be parsed at index 10
It looks like a bug for me.
I used this workaround:
String dateAsStr = '2014-04-23';
if (dateAsStr.length() == 10) {
dateAsStr += 'T00:00:00';
}
ZonedDateTime.parse(dateAsStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()));
If coming from Google:
Instead of doing:
ZonedDateTime.from(new Date().toInstant());
Try this:
ZonedDateTime.ofInstant(new Date(), ZoneId.of("UTC"));
Just an example conversions, I believe some folks will get the exception below
(java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: 2014-10-24T18:22:09.800Z of type java.time.Instant)
if they try
LocalDateTime localDateTime = LocalDateTime.from(new Date().toInstant());
to resolve the issue, please pass in Zone -
LocalDateTime localDateTime = LocalDateTime.from(new Date()
.toInstant().atZone(ZoneId.of("UTC")));

Comparing string object dates in Android Kotlin?

I'm using XmlPullParser to fetch and parse an RSS feed and store entries in a database. I'm storing the date as a String object in a format of "Dec 15, 2020" for example.
While I'm parsing the RSS feed I want to do a comparison to set a flag if the entry is before/after the data "Jan 1, 2021."
What would be the best way to do this? Is there a way to do it as strings or am I better off using Date objects?
You would parse the string as a LocalDate (because it seems that you are only comparing dates without timezone information) using the DateTimeFormatter from the modern Java/Kotlin time API in the java.time.* package.
In your case, since you want to parse a specific pattern, you would use DateTimeFormatter.ofPattern(pattern: String) to create the formatter. The whole class docs are available here
Then you would compare the parsed LocalDate to another LocalDate of your choice with .isBefore(other) or .isAfter(other) calls.
import java.time.LocalDate
import java.time.Month
import java.time.format.DateTimeFormatter
// ...
val rssDate = "Dec 15, 2020"
// your pattern
val dateFormatter = DateTimeFormatter.ofPattern("MMM d, yyyy")
val inputDate = LocalDate.parse(rssDate, dateFormatter)
val targetDate = LocalDate.of(2021, Month.JANUARY, 1)
if (inputDate.isBefore(targetDate)) {
// before
} else {
// after
}
Comparing date strings as strings, or otherwise dealing with dates (or time in general) without using a good time API will only lead to bugs. Also using the outdated older Java time APIs will eventually lead to bugs. Use the modern java.time.* API and beware of falsehoods we believe about time.
If you have to support older Android API levels (lower than 26) you need Android Gradle plugin of at least v4.0.0+ for the java.time.* APIs to be available (support for core library desugaring).

How to get hours from JodaTime with timezone

I encounter strange behaviour with Jodatime and Android. I want to parse string:
2014-05-19T18:13:00.000+02:00
to DateTime, and get year, month, hours to int. I started with some test on IntelliJ Studio, and I done something like that:
String date = "2014-05-19T18:13:00.000+02:00";
DateTime dateTime = new DateTime(date);
System.out.println(dateTime.toString());
System.out.println(dateTime.getYear());
System.out.println(dateTime.getMonthOfYear());
System.out.println(dateTime.getDayOfMonth());
System.out.println(dateTime.getHourOfDay());
System.out.println(dateTime.getMinuteOfHour());
System.out.println(dateTime.getMillis());
Which gave me correct answers:
2014-05-19T18:13:00.000+02:00
2014
5
19
18
13
1400515980000
Now, when I changed IDE to Android Studio, and do the same:
String dateT = "2014-05-19T18:13:00.000+02:00";
DateTime dateTime = new DateTime(dateT);
Lo.g(dateTime.getHourOfDay() + "");
Lo.g(dateTime.toString());
my results are:
16
2014-05-19T16:13:00.000Z
For some reason DateTime on Android Studio / Android not take into account the timezone which is +2:00.
I can not find solution for this. Also there is no simple method "addTimeZone" in Joda.
How to display correct time with DataTime? I tried LocalDateTime, construct DateTime with DateTimeZone.getDefault() (which gaves me UTF...)
Since you said that you use the same Joda-Time version on both platforms and regarding the fact that Joda-Time has its own timezone repository independent from system timezone data, there is probably only one explanation left why you observe different behaviour: Different input either explicit or implicit. Let's go into details:
Well, you say, obviously there is the same input given the same input string:
"2014-05-19T18:13:00.000+02:00"
So we have the same (explicit) input. But wait, there is another thing: implicit default settings which can also be considered as kind of input in an abstract way. You use the constructor DateTime(Object). This constructor first delegates to super constructor of class BaseDateTime as you can see in the source code.
public DateTime(Object instant) {
super(instant, (Chronology) null);
}
The javadoc of this super-constructor says:
"Constructs an instance from an Object that represents a datetime,
using the specified chronology. If the chronology is null, ISO in the
default time zone is used.
The recognised object types are defined in ConverterManager and
include ReadableInstant, String, Calendar and Date."
So finally we see that Joda-Time uses the default timezone. This is really the only possibility for different behaviour I can see by studying the source code and the documentation. All other things are equal: Same library version and same explicit string input and same test scenario.
Conclusion: You have different default timezones on your platforms. Note that you get the same instant on both platforms however, just represented with different local timestamps and offsets due to different internal timezone/offset setting inside the DateTime-object.
Update: I have tested the zone overriding behaviour with this code:
String date = "2014-05-19T19:13:00.000+03:00"; // same instant as yours (just with offset +03)
DateTime dateTime = new DateTime(date);
System.out.println(dateTime.toString());
// output: 2014-05-19T18:13:00.000+02:00 (in my default timezone Europe/Berlin)
So the default timezone has precedence over any offset in string input. If you instead want to use the parsed offset then look at using the DateTimeFormatter and its method withOffsetParsed().

How to obtain the locale date format on month and day

Im using Joda Time to format the dateTime as following:
DateTimeFormatter dateFormatter = DateTimeFormat.longDate();
String startTimeStr = dateFormatter.print(localStartTime);
The variables's values are:
localStartTime={org.joda.time.LocalDateTime#830018681648}"2013-04-06T23:54:35.000"
startTimeStr={java.lang.String#830018688880}"2013年4月6日"
Problem is how could I obtain the locale date format on month and day? I have tried the following codes:
DateTimeFormatter monDayFormatter = DateTimeFormat.forPattern("MMMd");
String startTimeStr = monDayFormatter.print(localStartTime);
and the variables's values are:
localStartTime={org.joda.time.LocalDateTime#830018681648}"2013-04-06T23:54:35.000"
startTimeStr={java.lang.String#830018683220}"4月6"
What I expected startTimeStr is 4月6日. Here the Chinese character 日 = Day.
I do not want to hard code the pattern to "MMMd日", because it should adjust itself according to the current locale information. Any help will be appreciated.
On the website of unicode consortium, you will find in Chinese CLDR repository for example entries like follows (calendar type = gregorian):
<dateFormats>
<dateFormatLength type="full">
<dateFormat>
<pattern>y年M月d日EEEE</pattern>
</dateFormat>
</dateFormatLength>
<dateFormatLength type="long">
<dateFormat>
<pattern>y年M月d日</pattern>
</dateFormat>
</dateFormatLength>
<dateFormatLength type="medium">
<dateFormat>
<pattern>y年M月d日</pattern>
</dateFormat>
</dateFormatLength>
<dateFormatLength type="short">
<dateFormat>
<pattern>yy/M/d</pattern>
</dateFormat>
</dateFormatLength>
</dateFormats>
Internally every localized date format either in JodaTime or in JDK dateformat classes will be translated to such a pattern - including literals like "日". CLDR does not define a month-day-only-format, but this is just a part of a general year-month-day-format, so if you use as replacement for
DateTimeFormatter dateFormatter = DateTimeFormat.longDate().withLocale(Locale.CHINESE);
LocalDateTime localStartTime = new LocalDateTime(2013,4,6,23,54,35);
String startTimeStr = dateFormatter.print(localStartTime);
System.out.println(startTimeStr); // output: 2013年4月6日
this code:
DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("M月d日");
LocalDateTime localStartTime = new LocalDateTime(2013,4,6,23,54,35);
String startTimeStr = dateFormatter.print(localStartTime);
System.out.println(startTimeStr); // output: 4月6日
then you get what you want. Although you write:
I do not want to hard code the pattern to "MMMd日"
that is pretty much the same procedure as done internally by libraries. So the pattern itself is localized by choosing the appropriate literals. There is no way to extract from CLDR a localized date pattern without year. If you want this, then you have to manage your own set of localized month-day-patterns for different locales, maybe in a Map<Locale, String>.
Update from 2016-12-06:
The situation not having a generic month-day-pattern for any locale has not changed for Joda-Time. Unfortunately the official successor of Joda-Time, the JSR-310 (java.time-package) does not manage it well, too, see the JDK-issue 8168532. This was reason enough for me to find a solution for my own time library Time4J in the mean-time. A close analysis of CLDR data has shown that there are other date formats available for many languages, but in a different section and accessible via a group of fields. The keys "Md", "MMMd" and "MMMMd" are relevant for your use-case. Example in Time4J (which should hopefully be supported by JSR-310, too, in a future release):
PlainTimestamp tsp = Iso8601Format.EXTENDED_DATE_TIME.parse("2013-04-06T23:54:35.000");
AnnualDate ad = AnnualDate.of(tsp.getMonth(), tsp.getDayOfMonth());
ChronoFormatter<AnnualDate> chinese =
ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.CHINESE, AnnualDate.chronology());
ChronoFormatter<AnnualDate> english =
ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.ENGLISH, AnnualDate.chronology());
System.out.println(chinese.format(ad)); // 4月6日
System.out.println(english.format(ad)); // Apr 6
It is also worth to note that the locale cannot be changed after construction of formatter in a sensible way because the localized pattern structure will be freezed during construction and is no longer sensible for later changes of locale. This will be improved in future release, however.
Here you go :
Calendar calendar = Calendar.getInstance();
SimpleDateFormat day_week = new SimpleDateFormat("EEEE");
SimpleDateFormat month_date = new SimpleDateFormat("MMMMMMMMM");
Date d = new Date();
String dayOfTheWeek = day_week.format(d);
String month = month_date.format(calendar.getTime());
Hope it helps.
Actually Android provides a helper class to deal with UTS #35 formatting, android.text.format.DateFormat.
In particular for this case, DateFormat.getBestDateTimePattern(locale, skeleton) since API Level 18.
So we can simplify things like this:
String bestFormat = DateFormat.getBestDateTimePattern(Locale.getDefault(), "MMMd");
String formatted = DateFormat.format(bestFormat, System.currentTimeMillis()).toString();
formatted would be "12月19日".
The behavior is confirmed on Android Q and Android O.

SQLite Datetime Conversion?

I m developing android application. I need to convert datetime into date. I want to convert '25-07-2013 11:44AM' (datetime) into '25-07-2013' (date).
I am trying this function to convert SELECT date('25-07-2013 11:44AM'), but it was not working.Please suggest some solution for this problem.
According to this page, it does not seem that am/pm times are supported in date SQLite function (this should be noted as h or K according to the date format specification of Java at least; also it is explicitly mentioned %H hour: 00-24). Maybe experiment if using 24 hour clock will not trigger the issue.
I am not sure if you are search for Java code or SQL code , but if it is Java code then solution could be this :
String date = "25-07-2014 11:44AM";
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
String newDate = dateFormat.format(dateFormat.parse(date));
System.out.println(newDate);
If in case your are looking for SQL code let me know I will share that as well.

Categories

Resources