Output "from Now" string in Kotlin using UTC timezone - android

I'm trying to write a Kotlin function which replicates the behaviour of fromNow in the moment library.
I have the following code:
fun formatDuration(dateTime: String): String {
try {
val parsedDateTime = Instant.parse(dateTime)
val prettyTime = PrettyTime()
prettyTime.reference = Instant.now().atZone(ZoneOffset.UTC).toInstant()
return prettyTime.format(parsedDateTime)
} catch (e: DateTimeParseException) {
e.printStackTrace()
return "Invalid date/time format"
}
}
The problem is when the device time is 9:44 and the input string is 2023-02-19T11:48:09.958Z, and the current UTC time is 15:19 it will output 2 hours from now, even though it should output 3 hours ago like the moment function does as the timestamp is in UTC.
How can I fix this to always take into account UTC time not local time when calculating the difference?

Have you tried to change:
from:
val parsedDateTime = Instant.parse(dateTime)
to:
val parsedDateTime = Instant.parse(dateTime).atZone(ZoneOffset.UTC).toInstant()

Related

How to parse date "2022-07-18T08:24:18Z" in android

I have tried these format but none worked.
yyyy-MM-dd'T'HH:mm:ss'Z'
yyyy-MM-dd'T'HH:mm:ssZ
yyyy-MM-dd'T'HH:mm:ssZZ
yyyy-MM-dd'T'HH:mm:ss
Also tried "ZonedDateTime", but it is not available below Android O.
If your minSDK is 25 or lower you have to use Java 8+ API desugaring support to be able to use the java.time package from Java 8.
With that enabled you can simply use e.g.
OffsetDateTime.parse("2022-07-18T08:24:18Z")
ZonedDateTime.parse("2022-07-18T08:24:18Z")
(you can find many resources about the differences of these date formats).
You can do it like this
fun parseDate(
inputDateString: String?,
inputDateFormat: SimpleDateFormat,
outputDateFormat: SimpleDateFormat
): String? {
var date: Date? = null
var outputDateString: String? = null
try {
date = inputDateFormat.parse(inputDateString)
outputDateString = outputDateFormat.format(date)
} catch (e: ParseException) {
e.printStackTrace()
}
return outputDateString
}
inputString will be your Date, ex:"2022-07-18T08:24:18Z"
inputDateFormat : SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
Locale.US)
outputDateFormat : in whichever format you want to show the date
I hope you get your answer from this

Convert Date String to Date object in Kotlin? How to calculate number of days between today and specific date in Kotlin?

Part 1:
I have date as string in the following format: "2020-10-15T22:54:54Z"
I have to convert it into date object.
Tried the following:
val dateString = "2020-10-15T22:54:54Z"
val dateFormatter = DateTimeFormatter.ofPattern("%Y-%m-%dT%H:%M:%SZ")
val updatedAtDate = LocalDate.parse(dateString, dateFormatter)
val today = LocalDateTime.now()
println("Updated At: $updatedAtDate")
Gives the following error: "Unknown pattern letter: T"
Part 2:
Once I have the date object from above, I have to calculate the difference between today (Current Date) and the above date. How to do it in Kotlin?
tl;dr You don't need to create a custom formatter…
… for the val dateString = "2020-10-15T22:54:54Z" here, it is formatted in an ISO standard. Therefore, you can simply do this (if you want a LocalDate, just year, month and day):
val thatDate: LocalDate = OffsetDateTime.parse(dateString).toLocalDate()
Fully adressing all the aspects of your post:
You can utilize a java.time.Period.between(LocalDate, LocalDate) in order to calculate the difference between two LocalDates. You only have to make sure the older date is the first argument, otherwise you will get a negative result. Here's a full example:
import java.time.OffsetDateTime
import java.time.LocalDate
import java.time.Period
fun main(args: Array<String>) {
val dateString = "2020-10-15T22:54:54Z"
// create an OffsetDateTime directly
val thatDate = OffsetDateTime.parse(dateString)
// and extract the date
.toLocalDate()
// get the current day (date only!)
val today = LocalDate.now()
// calculate the difference in days and make sure to get a positive result
val difference = if (today.isBefore(thatDate))
Period.between(today, thatDate).days
else
Period.between(thatDate, today).days
// print something containing both dates and the difference
println("[$today] Updated At: $thatDate, difference: $difference days")
}
Output at Dec 10, 2021:
[2021-12-10] Updated At: 2020-10-15, difference: 25 days

Selected date Month looks like a code not a string

Everyone
I'm using MaterialDatePicker to show the date and it was working fine and get the date like I want Aug 5,2021 and suddenly out of nowhere I get now Month like this M08 and that makes the date like this M08 5,2021
and below is the gradle dependency:
implementation "com.google.android.material:material:1.3.0"
Can anyone help me, please?
you can try this code
private fun showDatePicker() {
val selectedDateInMillis = currentSelectedDate ?: System.currentTimeMillis()
MaterialDatePicker.Builder.datePicker().setSelection(selectedDateInMillis).build().apply {
addOnPositiveButtonClickListener { dateInMillis -> onDateSelected(dateInMillis) }
}.show(supportFragmentManager, MaterialDatePicker::class.java.canonicalName)
}
// result onDateSelected
private fun onDateSelected(dateTimeStampInMillis: Long) {
currentSelectedDate = dateTimeStampInMillis
val dateTime: LocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(currentSelectedDate), ZoneId.systemDefault())
val dateAsFormattedText: String = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
// view for result
findViewById<TextView>(R.id.output).text = dateAsFormattedText
}
I found the issue. It was a localization issue need to verify localization for the material date picker before using it.

Why does Calendar.getDisplayName always return the same day of week when given milliseconds?

I'm trying to create an extension method to determine the name of the day within a week, given a specific Long value, so that it returns Monday, Tuesday, etc.
fun Long.convertFromLongToDayOfWeek(): String {
val calendar = Calendar.getInstance()
calendar.timeInMillis = this
return calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault()) ?: ""
}
however, regardless of the value I pass to the calendar instance, it always returns "Monday".
I've written a few unit tests with Long values (which I receive from an API) and they all return Monday. Values to test with include the following:
1601542800
1601715600
1601629200
This code is complete and inclusive up to here, the following unit tests are just there to simplify debugging:
#Test
fun testExample1() {
val value: Long = 1601542800
val result = value.convertFromLongToDayOfWeek()
Assert.assertEquals("Monday", result)
}
#Test
fun testExample2() {
val value: Long = 1601715600
val result = value.convertFromLongToDayOfWeek()
Assert.assertEquals("Monday", result)
}
both of these tests are passing, but neither of these Long values represent Monday, what am I doing wrong ?
Those are all Mondays! They're actually all the same Monday, there's 86,400,000 milliseconds in a day, and those values are only a few hundred seconds apart
If you're getting timestamps in seconds from an API, you need to multiply them by 1000 to get millis (which is what the Calendar setter takes)

App level kotlin function in android project

Can anybody explain how I can release an app-level kotlin function in Android Studio project? I have an Android application and I try do someting like this:
var date: Date = Date()
/////////////////////////////////////////////////////////
// this block must be app-level fun
val format = “dd.MM.yyyy”
val simpleDateFormat = SimpleDateFormat(format)
var formattedDate = simpleDateFormat.format(date)
/////////////////////////////////////////////////////////
convert Date object to String with custom format. I do it many times (in different activities and fragments) in my project, so I think it will be good idea to releas this code as function (or class, if it will be more efficient). Thus I have date and format as input parameters and formattedDate as output. Also it will be good to set default format value
You can create an extension function on Date that accepts a format and uses it to convert the date to that format. You can also define the default format on the input parameter. Something like:
fun Date.toFormattedString(format: String = "dd.MM.yyyy"): String {
val simpleDateFormat = SimpleDateFormat(format)
return simpleDateFormat.format(this)
}
Place it in a file where the whole app can access it (e.g., a file named Extensions.kt in a module/package where you put all reusable and/or helper code) and then just use the function like someDate.toFormattedString().
Here is an example of my function contained in separate kotlin file called Time.kt
fun timeConverter(string: String?, i: Int): String {
val isoFormat = "yyyy-MM-dd'T'HH:mm:ss"
var expectedFormat = "dd/MM"
when(i){
0 -> expectedFormat = "dd/MM"
1 -> expectedFormat = "EEE"
2 -> expectedFormat = "HH:mm"
3 -> expectedFormat = "EEE, dd/MM"
}
val dateFormat = SimpleDateFormat(isoFormat, Locale.getDefault())
val date = dateFormat.parse(string)
return SimpleDateFormat(expectedFormat).format(date)
}
Make the function part of an object.
https://www.baeldung.com/kotlin-objects
Objects (not class) in Kotlin are static. If you import the object from where you use the function, it can be used anywhere without being instantiated.
You can have a DateUtil class that holds a format function as companion. You will be able to use it anywhere in your app without instantiating it.
class DateUtil{
companion object {
fun format(date: Date):String{
val format = "dd.MM.yyyy"
val simpleDateFormat = SimpleDateFormat(format)
return simpleDateFormat.format(date)
}
}
}
Then you call it: DateUtil.format(Date())

Categories

Resources