Time between two dates in kotlin - android

I have a string as a date formatted yyyy-MM-dd, and I want to compare it with the current date. I'm using Android api24, and I want to be able to tell how much time has passed in a format like the first string.
I have tried with the Calendar class, something like this:
val firstDate=Calendar.getInstance()
val dateFormat=SimpleDateFormat("yyyy-MM-dd",Locale.getDefault())
firstDate.time=dateFormat.parse("2001-06-04")
but I get stuck here, getting the current time as a calendar object.

You can desugar to get to use the Java 8 datetime features:
Java 8+ APIs available through desugaring
Then it is really simple:
private fun convertFromString(datetime: String): LocalDateTime {
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.getDefault())
return LocalDateTime.parse(datetime, dateTimeFormatter)
}

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")));

How to get epoch milis from a date (LocalDate)

I have a month July 2022 for example, I want get epoch milis for the first day of the month
1st July 2022 at midnight.
from the month I was able to get the 1st July 2022, but how to convert it into epoch milis for 1st July 22 midnight
val datey = "July/2020"
val dateFormaty = DateTimeFormatter.ofPattern("MMMM/yyyy")
val yearMonthy = YearMonth.parse(datey, dateFormaty)
val parsedDatey = yearMonthy.atDay(1)
I get 2022-07-01 for parsedDate, I want to get the date time for this date in epoch milis
Thanks
R
Like I mentioned, LocalDate does not actually store any time information whatsoever, so transforming it to epoch isn't possible. Technically. Yet it is with some possible inacuracies.
How about something like this:
make the following extension function
fun LocalDate.toDate(): Date = Date.from(this.atStartOfDay(ZoneId.systemDefault()).toInstant())
Note that it uses the system default timezone for this, to provide the necessary information.
then just use it.
val myDate = myLocalDate.toDate()
which would in your case, be parsedDatey.toDate()
But, we don't really even need the Date here. Lets avoid casting the LocalDate to Date then getting the epoch milli from there, and just do it from the provided Instant instead.
So the real answer to your question is this:
fun LocalDate.getEpochMillis(): long = this.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()
// call this in your parsing method you posted
parsedDatey.getEpochMillis()

How to parse iso8601 date-time in android kotlin or java

Hello Devs,
I'm working on barcode scanner app, I get date and time at this pattern "20220610T230000Z"
I think its ISO8601 date-time format
However, I just want to parse this pattern so I can customize it as I want.
I tried this one:
val isoDate="20220610T230000Z" // from my barcode scanner
val df=SimpleDateFormat("yyyymmdd'T'HH:mm:ss.SSS'Z'")
val date= df.parse("20220610T230000Z")
but when i run code i get
java.text.parseexception unparseable
Thanks in advance
isoDate doesn't have any colons or periods in it. Since you're trying to turn isoDate into a Date object, you want something more like:
val df=SimpleDateFormat("yyyymmdd'T'HHmmssSSS'Z'")
Then, if you want to output a date String with different formatting, you'll have to create a different SimpleDateFormat instance (let's call it dt2) with the intended formatting, and call dt2.format(date). See here for a full example.
My issue solved
Thanks #OleV.V.
Solution
This pattern: "yyyyMMdd'T'HHmmss"

ThreeTenABP DateTime parser giving exception for yyyy-MM-ddTHH:mm:ss formate

I need to convert a dateTime String to millis and I am using ThreeTenABP for this, but the OffSetDateTime.parse is unable to parse the dateTime String which is for ex. "2020-08-14T20:05:00" and giving the following exception.
Caused by: org.threeten.bp.format.DateTimeParseException:
Text '2020-09-22T20:35:00' could not be parsed:
Unable to obtain OffsetDateTime from TemporalAccessor:
DateTimeBuilder[, ISO, null, 2020-09-22, 20:35], type org.threeten.bp.format.DateTimeBuilder
I have already searched through similar questions but could not find the exact solution.
Below is the code that I am using in Kotlin.
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss",
Locale.ROOT)
val givenDateString = event?.eventDateTime
val timeInMillis = OffsetDateTime.parse(givenDateString, formatter)
.toInstant()
.toEpochMilli()
The problem is the missing offset in the String that you are trying to parse to an OffsetDateTime. An OffsetDateTime cannot be created without a ZoneOffset but no ZoneOffset can be derived from this String (one could just guess it's UTC, but guessing is not suitable in such a situation).
You can parse the String to a LocalDateTime (a representation of a date and a time of day without a zone or an offset) and then add / attach the desired offset. You don't even need a custom DateTimeFormatter because your String is of ISO format and can be parsed using the default built-in formatter:
fun main() {
// example String
val givenDateString = "2020-09-22T20:35:00"
// determine the zone id of the device (you can alternatively set a fix one here)
val localZoneId: ZoneId = ZoneId.systemDefault()
// parse the String to a LocalDateTime
val localDateTime = LocalDateTime.parse(givenDateString)
// then create a ZonedDateTime by adding the zone id and convert it to an OffsetDateTime
val odt: OffsetDateTime = localDateTime.atZone(zoneId).toOffsetDateTime()
// get the time in epoch milliseconds
val timeInMillis = odt.toInstant().toEpochMilli()
// and print it
println("$odt ==> $timeInMillis")
}
this example code produces the following output (pay attention to the trailing Z in the datetime representation, that's an offset of +00:00 hours, the UTC time zone, I wrote this code in the Kotlin Playground and it seems to have UTC time zone ;-) ):
2020-09-22T20:35Z ==> 1600806900000
Please note that I tried this with java.time and not with the ThreeTen ABP, which is obsolete to use for many (lower) Android versions now, since there's Android API Desugaring. However, this shouldn't make a difference because your example code threw exactly the same exception when I tried it first, which means ThreeTen is not to blame for this.

How to save Timestamp value in Cloud Firestore and perform query on it?

I've followed this Stackoverflow post and there is clearly said how to store the timestamp, if we user the ServerTimestamp annotation. However, I want to ask about other alternatives, which can later also be used to perform queries on them.
With respect to the different time libraries (before/after Java 8) we can get the timestamp as a long variables, or as ZonedDateTime object. My question is:
Can we save ZonedDateTime object or a long variable as a String and then perform queries on it, or we must use in any case ServerTimestamp annotation?
If you want to write a timestamp field, and you can't use a server timestamp, you will need to either provide a regular Java Date object, or a Firebase Timestamp object. Either of these types of values will convert to a timestamp field in the document.
When you query for the document, the field will always show up in the document snapshot as a Timestamp type object.
I've figured it out. As you know when we're dealing with Time in Android, we need to pay attention to the different APIs i.e. APIs before API 26 and after that. There are many articles for this topic in Stackoverflow, but generalized, before Android 8 (Oreo, API 26) we need to use the library ThreeTenABP and after Android 8 we need to use java.time.
An implementation looks like this:
private Date getCurrentDate(){
if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
return Date.from(Instant.now());
} else {
AndroidThreeTen.init(this);
return DateTimeUtils.toDate(org.threeten.bp.Instant.now());
}
}
Of course, you can use LocalDateTime or ZonedDateTime etc.
Firebase expects Date object, or you can use the #ServerTimestamp annotation and provide no parameter in the constructor of your model. Firebase will then create the timestamp when request for saving data comes to it. Like this
//When you provide Date
class SomeClass {
private String someAttribute;
private Date someDate;
...
public SomeClass(String someAttribute, Date someDate, ...){
this.someAttribute = someAttribute;
this.someDate = someDate;
}
}
//When you don't provide Date
class SomeClass {
private String someAttribute;
private #ServerTimestamp Date someDate;
...
public SomeClass(String someAttribute, ...){
this.someAttribute = someAttribute;
...
}
}
(In may case I needed the Date object when I start an activity, but a request to the server may happen even after 2-3 hours. That's why #ServerTimestamp was inefficient for me.)
The retrieving happens in the same way. Create a model class, or use HashMap (your choice) but the type must be Date. It holds almost every kind of information according to date and time (time zone, the time is even up to microseconds etc).
Most of the time, the user wants to see only a date and a time in form of hours:minutes.
You can use DateTimeFormatter and provide the pattern which you want (there are plenty of standards). In my case I use it in this way:
private String formatDate(Date date){
if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
java.time.LocalDateTime ldt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
java.time.format.DateTimeFormatter dtf = java.time.format.DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
return ldt.format(dtf);
} else {
LocalDateTime ldt = Instant.ofEpochMilli(date.getTime()).atZone(org.threeten.bp.ZoneId.systemDefault()).toLocalDateTime();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
return ldt.format(dtf);
}
}
As you see the method expects a Date object (what you retrieve from Firebase). Then it will remove most of the irrelevant data (in my case) and return you only the date and the time in the specified format.
(Note: in this post where UPDATE 2020/01/17 is, a colleague points that with Android Studio 4.0 we can use Java 8 in older APIs as well (like in my case - API 21), but I didn't dig into the topic concrete. You can check it also :)

Categories

Resources