I'm trying to make a string format that, when a user post is uploaded, it expresses the upload time as "~ minutes ago" or "~ hours ago" and so on.
My application works in the way like below
upload post in PostActivity > firebase saves the data of the post (the post is consist of postId, writerId, message, writeTime, bgUri for image, commentCount) > MainActivity gets data from firebase and shows the post on RecycleView by MyAdapter.kt
Below is the PostActivity.kt
class PostActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_post)
supportActionBar?.title = "New Post"
val layoutManager = LinearLayoutManager(this@PostActivity)
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
recyclerView2.layoutManager=layoutManager
recyclerView2.adapter = MyAdapter()
postButton.setOnClickListener {
val newRef = FirebaseDatabase.getInstance().getReference("Posts").push()
post.writeTime= DateTime().toString()
newRef.setValue(post)
finish()
}
}
The writeTime
field of post
is DateTime().toString().
For the string format, I made a function getdiffTimeText()
at MyAdapter.kt
which is below.
class MyAdapter(private val posts : MutableList<Post>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() { //line 20
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val post = posts[position]
holder.timeTextView.text = getDiffTimeText(post.writeTime) //line 32
}
public class MyViewHolder(itemView : View) :
val timeTextView = itemView?.findViewById<TextView>(R.id.timeTextView) //line 51
}
}
fun getDiffTimeText(targetTime: String): String {
val curDateTime = DateTime()
val targetDateTime = DateTime(targetTime)
val diffDay = Days.daysBetween(curDateTime, targetDateTime).days
val diffHours = Hours.hoursBetween(targetDateTime, curDateTime).hours
val diffMinutes = Minutes.minutesBetween(targetDateTime, curDateTime).minutes
if (diffDay == 0) {
if (diffDay == 0 && diffMinutes == 0) {
return "just before"
}
return if (diffHours > 0) {
"" + diffHours + "hours ago"
} else "" + diffMinutes + "minutes ago"
} else {
val format = SimpleDateFormat("yyyy.MM.dd")
return format.format(Date(targetTime))
}
}
Below is the MainActivity
class MainActivity : AppCompatActivity() {
val posts: MutableList<Post> = mutableListOf()
private lateinit var dbref: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getUserData()
}
private fun getUserData() {
dbref = FirebaseDatabase.getInstance().getReference("/Posts")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (userSnapshot in snapshot.children) {
val post = userSnapshot.getValue(Post::class.java)
posts.add(post!!)
}
recyclerView_main.adapter = MyAdapter(posts)
}
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(this@MainActivity,"failed",Toast.LENGTH_SHORT).show()
}
})
}
}
Below is Post.kt the class of user's post.
class Post {
var postId = ""
var writerId = ""
var message = ""
var writeTime = ""
var bgUri = ""
var commentCount = ""
}
When I run the code, app crashes with the error below.
java.lang.IllegalArgumentException: Invalid format: "1661861458" is malformed at "8"
at org.joda.time.DateTime.<init>(DateTime.java:257)
at <<package name>>.MyAdapterKt.getDiffTimeText(MyAdapter.kt:51)
at <<package name>>.MyAdapter.onBindViewHolder(MyAdapter.kt:32)
at <<package name>>.MyAdapter.onBindViewHolder(MyAdapter.kt:20)
To test the fuction getDiffTimeText()
I tried the code below in different activity.
val testTime = DateTime().toString()
val testText = findViewById<TextView>(R.id.testing)
val testText2 = findViewById<TextView>(R.id.testing2)
testText.text = testTime
testText2.text = getDiffTimeText(testTime)
The testTime
is String type just like the Post.kt where the type of writeTime field is String.
As the result, textview testText
shows 2022-08-31T05:37:55.778Z
which is the current time, and testText2
shows just ago
. So it seems the function getDiffTimeText
works in this way. But It doesn't work in holder.timeTextView.text = getDiffTimeText(post.writeTime)
which is MyAdapter.kt
line 32, and the app crashes. How should I solve this?
*edited my question for clearence, codes that are less relevant are excluded.
Seem the timestamp you passed in line 32 holder.timeTextView.text = getDiffTimeText(post.writeTime)
is counting with second instead of millis.
You can try to changed your remote time to millis or just do like that:
val timeInMillis = post.writeTime.toLong() * 1000L // maybe toLongOrNull() for safe usage.
holder.timeTextView.text = getDiffTimeText(timeInMillis.toString())
I used this approach to fix my issue: Though in my case I was just calculating the time and not date. But you can have some idea.
So I was trying to store the time in milliseconds and then retrieving it back to show in a desired format:
Here are the steps I followed:
First saving the time in database
val h = picker.hour
val m = picker.minute
val hour = TimeUnit.HOURS.toMillis(h.toLong())
val minute = TimeUnit.MINUTES.toMillis(m.toLong())
val totalTime = hour + minute
Now retrieving the time from database
val timeMilliseconds = totalTime.toLong()
val startTime = formatToDigitalClock(timeMilliseconds)
//Converting received long time to proper digital format
private fun formatToDigitalClock(milliseconds: Long): String {
val hours = TimeUnit.MILLISECONDS.toHours(milliseconds).toInt() % 24
val minutes = TimeUnit.MILLISECONDS.toMinutes(milliseconds).toInt() % 60
val seconds = TimeUnit.MILLISECONDS.toSeconds(milliseconds).toInt() % 60
return when {
hours > 0 -> String.format("%d:%02d:%02d", hours, minutes, seconds)
minutes > 0 -> String.format("%02d:%02d", minutes, seconds)
seconds > 0 -> String.format("00:%02d", seconds)
else -> {
"00:00"
}
}
}
You can further change the String format in a way so that you can show your time like ("2 hours ago")
If post.writeTime.toLong()
causes a java.lang.NumberFormatException: For input string: "2022-08-31T04:20:45.265Z"
, I'll have to conclude that the type of post.writeTime
is String
in ISO standard.
There's a simple way to parse those ISO standards in java.time
, in this case you can do
OffsetDateTime.parse(post.writeTime)
and use that to calculate the difference / time elapsed until now (in code: OffsetDateTime.now(ZoneOffset.UTC)
). You will need a ZoneOffset
because the String
returned by post.writeTime
also has one (the Z
at the end is UTC resp. an offset of +00:00 hours).
The elapsed time can be calculated by means of a java.time.Duration
:
val duration = Duration.between(
OffsetDateTime.parse(post.writeTime),
OffsetDateTime.now(ZoneOffset.UTC)
)
A Duration
represents elapsed time in hours, minutes, seconds, millis and even nanos, I think. However, only hours, minutes and seconds should matter here (correct me if I'm wrong).
Now the Kotlin magic comes into play: We can write an extension function for Duration
, one that simply checks the values top-down (hours first, if zero, use minutes, if zero, use seconds, if zero write some statement):
fun Duration.timeAgo(): String {
return when {
this.toHours() > 0 -> "${this.toHours()} hours ago"
this.toMinutes() > 0 -> "${this.toMinutes()} minutes ago"
this.toSeconds() > 0 -> "${this.toSeconds()} seconds ago"
else -> "a moment ago"
}
}
Example in a main
using the time String
from your comment below another answer and the code mentioned above (in this answer):
fun main() {
val duration = Duration.between(
OffsetDateTime.parse("2022-08-31T04:20:45.265Z"),
OffsetDateTime.now(ZoneOffset.UTC)
)
println(duration.timeAgo())
}
Result (attention, it depends on the runtime of the code):
3 hours ago
Some examples with Duration
s of differen values:
fun main() {
val durOne = Duration.ofHours(2).plusMinutes(13).plusSeconds(53)
val durTwo = Duration.ofMinutes(13).plusSeconds(53)
val durThree = Duration.ofSeconds(53).plusMillis(20)
val durFour = Duration.ofMillis(20)
println("${durOne.timeAgo()}")
println("${durTwo.timeAgo()}")
println("${durThree.timeAgo()}")
println("${durFour.timeAgo()}")
}
Output:
2 hours ago
13 minutes ago
53 seconds ago
a moment ago
there were data on my database which I stored before, and I missed that those data had different structure about writetime. So that caused the crash on loading data. After removing those, it worked well.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.