0

I want to generate an array of date objects Kotlin style, from current day descending each 5 days programmatically:

{now, 5_days_ago, 10_days_ago, etc..}

private fun dateArray() : ArrayList<Date> {
    val date = Date()
    val date2 = Date(date.time - 432000000)
    val date3 = Date(date2.time - 432000000)
    val date4 = Date(date3.time - 432000000)
    val date5 = Date(date4.time - 432000000)
    val date6 = Date(date5.time - 432000000)
    val date7 = Date(date6.time - 432000000)
    val date8 = Date(date7.time - 432000000)
    val date9 = Date(date8.time - 432000000)
    val dateA = Date(date9.time - 432000000)
    return arrayListOf(date, date2, date3, date4, date5, date6, date7, date8, date9, dateA)
}

This way is to much overheaded. I bet Kotlin offers an elegant way?

Syscall
  • 19,327
  • 10
  • 37
  • 52
Pavel Pipovic
  • 339
  • 1
  • 3
  • 12
  • How are you verifying no array is generated? Calling a constructor absolutely instantiates an object. – Tenfour04 Sep 09 '20 at 21:26
  • What He Said!  At first glance, that code looks about right.  Though I'd check whether you should be using DAY_OF_MONTH rather than DAY_OF_YEAR.  Also, it's generally recommended to use the newer java.time classes — LocalDate, Instant, &c — than the old clunky java.util classes such as Date and Calendar. – gidds Sep 09 '20 at 21:32
  • @gidds But what about 09.09 , 04.09 , 30.08 , 25.08 , 20.08 , 15.08 , .... With DAY_OF_MONTH can I overflow from September to August? – Pavel Pipovic Sep 09 '20 at 21:58
  • @pavel Check the documentation for Calendar.add(); it does proper date calculations that 'carry' between the different units. (Unlike the Calendar.roll() methods, which don't.) – gidds Sep 09 '20 at 22:36
  • I recommend you don’t use `Date` (and not `Calendar` either). Those classes are poorly designed and long outdated. Instead use `LocalDate` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Sep 14 '20 at 17:52
  • @ArvindKumarAvinash I was asking for a Kotlin style solution.. an elegant Kotlin way - not good old Java. – Pavel Pipovic Sep 15 '20 at 20:20

2 Answers2

1

java.time

Here’s a simple pure Java solution. Like others I am recommending that you use java.time, the modern Java date and time API, for your date work.

    Period step = Period.ofDays(-5);
    int numberOfDates = 10;
    
    Period totalPeriod = step.multipliedBy(numberOfDates);
    
    LocalDate today = LocalDate.now(ZoneId.of("America/Rosario"));
    List<LocalDate> dates = today.datesUntil(today.plus(totalPeriod), step)
            .collect(Collectors.toList());
    
    System.out.println(dates);

Output:

[2020-09-14, 2020-09-09, 2020-09-04, 2020-08-30, 2020-08-25, 2020-08-20, 2020-08-15, 2020-08-10, 2020-08-05, 2020-07-31]

I trust that you can translate to Kotlin and maybe even refine it further in Kotlin.

It’s not well documented that you may use the two-arg LocalDate.datesUntil() with a negative period, but at least it works on my Java 11.

Sorry to say, your solution in the question not only has more code than needed, it is also incorrect. Subtracting 432 000 000 milliseconds each time assumes that a day is always 24 hours. Because of summer time (DST) and other time anomalies a day may be 23 or 25 hours or something in between. By using LocalDate we are free of such issues. You may also use for example ZonedDateTime of LocalDateTime instead if you want to include time of day, they work fine across summer time transitions too.

Link: Oracle tutorial: Date Time explaining how to use java.time.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

I recommend you switch from the outdated and error-prone java.util date-time API to the modern java.time date-time API. Learn more about the modern date-time API from Trail: Date Time. If your Android API level is still not compliant with Java8, check How to use ThreeTenABP in Android Project and Java 8+ APIs available through desugaring.

Do it as follows using the Java modern date-time API:

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Tests
        System.out.println(getPastDaysOnIntervalOf(10, 5));// 10 days in past at an interval of 5 days
        System.out.println(getPastDaysOnIntervalOf(5, 10));// 5 days in past at an interval of 10 days
    }

    static List<LocalDate> getPastDaysOnIntervalOf(int times, int interval) {
        // The list to be populated with the desired dates
        List<LocalDate> list = new ArrayList<>();

        // Today
        LocalDate date = LocalDate.now();

        for (int i = 1; i <= times; i++) {
            list.add(date);
            date = date.minusDays(interval);
        }

        // Return the populated list
        return list;
    }
}

Output:

[2020-09-14, 2020-09-09, 2020-09-04, 2020-08-30, 2020-08-25, 2020-08-20, 2020-08-15, 2020-08-10, 2020-08-05, 2020-07-31]
[2020-09-14, 2020-09-04, 2020-08-25, 2020-08-15, 2020-08-05]

Using legacy API:

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Tests
        System.out.println(getPastDaysOnIntervalOf(10, 5));// 10 days in past at an interval of 5 days
        System.out.println(getPastDaysOnIntervalOf(5, 10));// 5 days in past at an interval of 10 days
    }

    static List<Date> getPastDaysOnIntervalOf(int times, int interval) {
        // The list to be populated with the desired dates
        List<Date> list = new ArrayList<>();

        // Today
        Calendar cal = Calendar.getInstance();
        Date date = cal.getTime();

        for (int i = 1; i <= times; i++) {
            list.add(date);
            cal.add(Calendar.DATE, -interval);
            date = cal.getTime();
        }

        // Return the populated list
        return list;
    }
}
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110