How can I get the dates of the current week using kotlinx.datetime KMM library?
eg. I want to get a list of current week's date like:
("Monday, 07", "Tuesday, 08", "Wednesday, 09", ... )
This is a similar impementation using Calendar:
fun getDaysOfWeek(): Array<String?> {
val dateFormat = SimpleDateFormat("EEEEE\ndd", Locale.getDefault())
val calendar = Calendar.getInstance()
calendar.firstDayOfWeek = Calendar.MONDAY
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
val days = arrayOfNulls<String>(7)
for (i in 0..6) {
days[i] = dateFormat.format(calendar.time)
calendar.add(Calendar.DAY_OF_MONTH, 1)
}
return days
}
val today = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
val days = mutableListOf<LocalDate>()
val firstWeekDay = today.daysShift(-DayOfWeek.values().indexOf(today.dayOfWeek))
for (i in 0 until DayOfWeek.values().count()) {
days.add(firstWeekDay.daysShift(i))
}
val dayStrings = days.map { "${it.dayOfWeek}, ${it.dayOfMonth}" }
println("$dayStrings")
fun LocalDate.daysShift(days: Int): LocalDate = when {
days < 0 -> {
minus(DateTimeUnit.DayBased(-days))
}
days > 0 -> {
plus(DateTimeUnit.DayBased(days))
}
else -> this
}
Related
What I am trying to do is given a list of objects responseList<Object> in which the objects have a date field on string format "2015-01-16", filter the list to only get objects form last month or the current year and add the filtered objects to a new list.
The first thing that I have done is convert the string into date and the result is "Fri Jan 16 00:00:00 GMT-05:00 2015".
using:
val dateformated = getFormatedDate(object.date)
val cal = Calendar.getInstance()
cal.time = dateFormated; //date formatted is the string converted to date
var responseMonth = cal.get(Calendar.MONTH)
var responseYear = cal.get(Calendar.YEAR)
I am able to retrieve both month and year of the response and using this:
val now: LocalDate = LocalDate.now()
val lastMonth = now.minusMonths(1).month
val thisYear = now.year
I get the current year and month
What I am failing to is filtering the object list based on the requirement to create another list.
Any help or suggestions would be great, thanks
#Test
fun filterDateListByLastMonthOrThisYear() {
val fakeDateOne = LocalDate.of(2023, 2, 1)
val fakeDateTwo = LocalDate.of(2020, 3, 12)
val fakeDateThree = LocalDate.of(1999, 12, 31)
val fakeDateFour = LocalDate.of(2023, 2, 2)
val fakeDateFive = LocalDate.of(2023, 1, 3)
val datesList = listOf(
fakeDateOne,
fakeDateTwo,
fakeDateThree,
fakeDateFour,
fakeDateFive
)
val today = LocalDate.now()
val lastMonth = today.month.minus(1)
val thisYear = today.year
val expected = listOf(fakeDateOne, fakeDateFour, fakeDateFive)
val actual = datesList.filter { it.year == thisYear || it.month == lastMonth }
assertEquals(expected, actual)
}
i have a project that should bring end date after the start date on android datepicker.
(user will chose any date on start date and when user click end date what ever user choose end date should be one day after start date)
for this purpose i have a Kotlin code as in below;
private fun showDatePickerDialog(type: Int) {
calendar = Calendar.getInstance()
year = calendar!!.get(Calendar.YEAR)
month = calendar!!.get(Calendar.MONTH)
dayOfMonth = calendar!!.get(Calendar.DAY_OF_MONTH)
datePickerDialog = DatePickerDialog(
requireContext(), R.style.MyDatePickerStyle,
{ datePicker, year, month, day ->
if (type == 0){
var month = month + 1
var startMonthConverted = ""+month
var startDayConverted = ""+day
if(month<10){
startMonthConverted = "0$startMonthConverted"
}
if(day<10){
startDayConverted= "0$startDayConverted"
}
binding.txtStartDate.setText("$year-$startMonthConverted-$startDayConverted")
} else {
var month = month + 1
var monthConverted = ""+month
var dayConverted = ""+day
if(month<10){
monthConverted = "0$monthConverted";
}
if(day<10){
dayConverted = "0$dayConverted"
}
binding.txtEndDate.setText("$year-$monthConverted-$dayConverted")
}
},
year,
month,
dayOfMonth
)
if (type == 0) {
val startDay = Calendar.getInstance()
startDay.add(Calendar.DAY_OF_YEAR, 2);
datePickerDialog!!.datePicker.minDate = startDay.timeInMillis
} else {
val endDay = Calendar.getInstance()
endDay.add(Calendar.DATE, 2)
// datePickerDialog!!.datePicker.minDate = endDay.timeInMillis
datePickerDialog!!.getDatePicker().setMinDate(endDay.getTimeInMillis());
}
val df: DateFormat = SimpleDateFormat("'T'HH:mm:ss.SSS")
currentTime = df.format(Calendar.getInstance().timeInMillis)
Log.d("TAG", "currentTime:$currentTime ")
datePickerDialog!!.show()
//set OK/Cancel buttons color
//set OK/Cancel buttons color
datePickerDialog!!.getButton(Dialog.BUTTON_POSITIVE)
.setTextColor(android.graphics.Color.BLACK)
datePickerDialog!!.getButton(Dialog.BUTTON_NEGATIVE)
.setTextColor(android.graphics.Color.BLACK)
}
Below is the function I am using to diplay date picker dialog in android.
private fun openPurchaseDatePickerDialog(
yearToDisplay: Int,
monthToDisplay: Int,
dayToDisplay: Int
) {
try {
activity?.let { KeyboardUtils.hideKeyboard(it) }
val calendar = Calendar.getInstance()
val dialog = DatePickerDialog(activity, { _, year, month, day_of_month ->
calendar[Calendar.YEAR] = year
calendar[Calendar.MONTH] = month
calendar[Calendar.DAY_OF_MONTH] = day_of_month
val myFormat = "" + DateUtils.OverAllAppDateDisplayFormat
val sdf = SimpleDateFormat(myFormat, Locale.getDefault())
edtPurchaseDate.setText(sdf.format(calendar.time).toString())
spIntendedUse.isFocusable = true
}, yearToDisplay, monthToDisplay, dayToDisplay)
dialog.updateDate(yearToDisplay,monthToDisplay,dayToDisplay)
dialog.datePicker.maxDate = calendar.timeInMillis
dialog.show()
} catch (e: Exception) {
e.printStackTrace()
}
As above you can check that there are three arguments passed in this function.
I have to show the specific date in DatePicker dialog show I have passed this three parameters.
Means If User selected the date first time the default values will be set or the current date will be set.
If edittext has already a text selected and not empty am doing as below :
if (edtPurchaseDate.text.toString().isNullOrEmpty()) {
val calendar = Calendar.getInstance()
openPurchaseDatePickerDialog(
calendar[Calendar.YEAR],
calendar[Calendar.MONTH],
calendar[Calendar.DAY_OF_MONTH]
)
} else {
var dateArr = edtPurchaseDate.text.toString().split("-")
openPurchaseDatePickerDialog(
dateArr[2].toInt(),
dateArr[1].toInt(),
dateArr[0].toInt()
)
}
But Still when the date picker dialogs opens its displaying the selected as as today instead of custom.
What might be the issue?
You can see I have also tried with updateDate() function as below :
dialog.updateDate(yearToDisplay,monthToDisplay,dayToDisplay)
Thanks.
Not completely sure about the updateDate method issue here . But to fix this you can use same Calendar object during initialization it should work fine .
i have modified your method a bit .
private fun openPurchaseDatePickerDialog(date: String) {
try {
val calendar = Calendar.getInstance()
if (date.isNotBlank()) {
try {
calendar.time = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).parse(date)!!
}catch (e:ParseException){
}
}
val dialog = DatePickerDialog(this, { _, year, month, day_of_month ->
calendar[Calendar.YEAR] = year
calendar[Calendar.MONTH] = month
calendar[Calendar.DAY_OF_MONTH] = day_of_month
val myFormat = "dd-MM-yyyy"
val sdf = SimpleDateFormat(myFormat, Locale.getDefault())
edtPurchaseDate.setText(sdf.format(calendar.time).toString())
}, calendar[Calendar.YEAR], calendar[Calendar.MONTH], calendar[Calendar.DAY_OF_MONTH])
dialog.datePicker.maxDate = System.currentTimeMillis()
dialog.show()
} catch (e: Exception) {
e.printStackTrace()
}
}
Now when you call it you just call it with a value you do mnot have to split String.
openPurchaseDatePickerDialog(edtPurchaseDate.text.toString())
I am trying to work on displaying dates and I am experiencing a challenge. So I have this one textview in my adapter class and I want the time displayed to be in 3 different format, Say for instance when its past 24hrs say date e.g Saturday if its very old just display date 02/9/2021 and if a day has not ended just display time 12:00am my problem is how do I achieve this on Android using Kotlin? here is a sample image I got
It's simple just get difference between now and your date and use SimpleDateFormat to formate date
fun getDate(date:Long){
val nowCal = Calendar.getInstance()
val dateCal = Calendar.getInstance().apply {
//just for test, replace with your date timestamp
timeInMillis += TimeUnit.DAYS.toMillis(9)
}
val nowDay = TimeUnit.MILLISECONDS.toDays(nowCal.timeInMillis)
val dateDay = TimeUnit.MILLISECONDS.toDays(dateCal.timeInMillis)
when {
(dateDay - nowDay) <= 1L -> {
val formatter = SimpleDateFormat("hh:mm a")
val dateStr = formatter.format(dateCal.time)
println(dateStr)
}
(dateDay - nowDay) <= 6L -> {
val dateStr = dateCal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.ENGLISH)
println(dateStr)
}
else ->{
val formatter = SimpleDateFormat("M/d/yy")
val dateStr = formatter.format(dateCal.time)
println(dateStr)
}
}
}
I have a date in the future and have to format the remaining time until this day like so.
4 days
1 month, 4 days
1 year, 1 month
I have looked at the DateUtils documentation but haven't seen this exact format.
I'm also fine using an external library like threetenabp.
Is there a library that can handle both the time calculation and the localization of the strings?
I wrote this blog a while ago, it shows how to do the opposite of what you are asking :-) https://blog.blundellapps.co.uk/creating-comments-with-timestamps-like-youtube/ i.e. given a time, say how long ago that was.
Android also offers this solution for times in the past: https://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeDateTimeString(android.content.Context,%20long,%20long,%20long,%20int).
So you need the opposite of these!
It should not be too hard to inverse. Instead of using the time now and negating the difference of a time in the past. You use the time now and add the time in the future.
So the inverse of: https://github.com/blundell/YouTubeTimeStamps/blob/master/app/src/main/java/com/blundell/tut/TimeStampFormatter.kt
The main difference being you want a difference between now and a date in the future, like so:
private fun getMillisFromNow(futureTime: Date): Long {
val futureTimeMillis = futureTime.time
val nowMillis = System.currentTimeMillis()
return futureTimeMillis - nowMillis
}
And then format it. Something like this:
fun format(timestamp: Date): String {
val millisFromNow = getMillisFromNow(timestamp)
val minutesFromNow = TimeUnit.MILLISECONDS.toMinutes(millisFromNow)
if (minutesFromNow < 1) {
return "about now"
}
val hoursFromNow = TimeUnit.MILLISECONDS.toHours(millisFromNow)
if (hoursFromNow < 1) {
return formatMinutes(minutesFromNow)
}
val daysFromNow = TimeUnit.MILLISECONDS.toDays(millisFromNow)
if (daysFromNow < 1) {
return formatHours(hoursFromNow)
}
val weeksFromNow = TimeUnit.MILLISECONDS.toDays(millisFromNow) / 7
if (weeksFromNow < 1) {
return formatDays(daysFromNow)
}
val monthsFromNow = TimeUnit.MILLISECONDS.toDays(millisFromNow) / 30
if (monthsFromNow < 1) {
return formatWeeks(weeksFromNow)
}
val yearsFromNow = TimeUnit.MILLISECONDS.toDays(millisFromNow) / 365
return if (yearsFromNow < 1) {
formatMonths(monthsFromNow)
} else formatYears(yearsFromNow)
}
private fun getMillisFromNow(futureTime: Date): Long {
val futureTimeMillis = futureTime.time
val nowMillis = System.currentTimeMillis()
return futureTimeMillis - nowMillis
}
private fun formatMinutes(minutes: Long): String {
return format(minutes, " minute to go", " minutes to go")
}
private fun formatHours(hours: Long): String {
return format(hours, " hour to go", " hours to go")
}
private fun formatDays(days: Long): String {
return format(days, " day to go", " days to go")
}
private fun formatWeeks(weeks: Long): String {
return format(weeks, " week to go", " weeks to go")
}
private fun formatMonths(months: Long): String {
return format(months, " month to go", " months to go")
}
private fun formatYears(years: Long): String {
return format(years, " year to go", " years to go")
}
private fun format(hand: Long, singular: String, plural: String): String {
return if (hand == 1L) {
hand.toString() + singular
} else {
hand.toString() + plural
}
}
Just sanity checked it with this test:
#Test
fun test() {
val twoDaysInMillisInstant = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(50))
val result = format(Date.from(twoDaysInMillisInstant))
assertEquals("2 days to go", result)
}
For the localization, you can convert this to using Strings.xml.
using threeten's LocalDate you can get the remaining years, months and day from one date to another. Having that values you can 0-check them and show only ones that are > 0.
Simple example:
val futureDate = LocalDate.of(2020,2,20)
val todayDate = LocalDate.now()
val remainingYears = futureDate.year - todayDate.year //output 0
val remainingMonth = futureDate.monthValue - todayDate.monthValue //output 0
val remainingDays = futureDate.dayOfMonth - todayDate.dayOfMonth // output 16
I hope that is what you wanted, cheers!