Search code examples
javastringdateformattingepoch

Properly working with dates that comes as a string value and compare them


In my program, I have a bunch of strings that represent dates and looks like this:

String someDate1 = "abcd-2020-02-19t10:23:31.180z";
String someDate2 = "xyz-2020-02-22t10:03:31.111z";
String someDate2 = "blablabla-2020-06-15t11:13:31.181z";

Let's take "someDate1" for example, I've managed to trim those strings so I'll end up having only the date by doing this for example:

System.out.println(someDate1.substring(someDate1.length() - 24).substring(0, 19));

output:

2020-02-19t10:23:31

now, I want to determine whether or not this date at the output is older than seven days or not.

let's say I keep the string above in a list, so all I want is simply to know if my date is older than a week or not something like:

public static void main(String[] args) {

    String someDate1 = "abcd-2020-02-19t10:23:31.180z";
    List<String> datesList = new ArrayList<>();
    datesList.add(someDate1);
    ...//adding others too

    datesList.forEach(date -> {
        if (isDateOlder(date)) {
            System.out.println(date + " - this is more than 7 days old, it has been more than a week!");
        }
        else {
            System.out.println(date + " - it has NOT been more than a week since this date!");
        }
    });
}


static boolean isDateOlder(String date) { 
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
    String afterTrimming = date.substring(date.length() - 24).substring(0, 19).replace("t", "-");

    try {
        Date afterFormatParse = formatter.parse(afterTrimming);

        LocalDate weekAgo = LocalDate.now().minusDays(7); //cool thing you can do, but i'm not using it
        System.out.println("a week ago : " + weekAgo); //it seems useful but i don't really use it because I saw I can't compare "Date" with LocalDate

        long rn = new Date().toInstant().toEpochMilli();
        long weekInMillis = 604800000;
        long oneWeekAgo = rn - weekInMillis;


        if (afterFormatParse.toInstant().toEpochMilli() <= oneWeekAgo) {
            return true;
        }
        else {
            return false;
        }

    } catch (ParseException e) {
        e.printStackTrace();
    }


}

The bottom line is, it works, but this seems very naive/wasteful and I'm sure there's a more clever way... so basically my main question is:

It's too bad that LocalDate doesn't have "toDate()" method so you would be able to compare between the two when you need to, in the end, I used a 'fixed epoch" in a variable to represent a week, which is very naive. I'd like to hear if you guys have a prettier way to represent a date minus a week like LocalDate offers and at the same time, a way to compare between one another?

  • note: I've also taken a try with isBefore() like so:

    afterFormatParse.toInstant().isBefore(LocalDate.now().minusDays(7)) but it can't be done because "LocalDate.now().minusDays(7)" is LocalDate type and not Instant type, and when Using Date i don't have the ".minusDays(7)" ability anymore

  • note 2: in reality, my strings sometimes starts with "add-vvd-sfsf-...." or more that's why I'm trimming from the end

thanks a lot.


Solution

  • 2020-02-19t10:23:31.180z is in a standard ISO 8601 date format, natively supported by the Java 8+ Time API, so there is no need to use a custom format pattern.

    As such, to check if the date is more than 7 days in the past, to the fractional second, you can do it like this:

    static boolean isDateOlder(String dateStr) {
        Instant date = Instant.parse(dateStr.substring(dateStr.indexOf('-') + 1));
        Instant weekAgo = ZonedDateTime.now().minusDays(7).toInstant();
        return date.isBefore(weekAgo);
    }
    

    If you want to ignore the time part and the time zone offset (compare date parts only), you can do it like this:

    static boolean isDateOlder(String dateStr) {
        LocalDate date = LocalDate.parse(dateStr.substring(dateStr.indexOf('-') + 1),
                                         DateTimeFormatter.ISO_DATE_TIME);
        LocalDate weekAgo = LocalDate.now().minusDays(7);
        return date.isBefore(weekAgo);
    }
    

    To adjust the UTC time zone offset (e.g. Z) in the input to the local time zone, then compare pure dates (in case time zone shift crosses midnight), you can do it like this:

    static boolean isDateOlder(String dateStr) {
        LocalDate date = Instant.parse(dateStr.substring(dateStr.indexOf('-') + 1))
                                .atZone(ZoneId.systemDefault())
                                .toLocalDate();
        LocalDate weekAgo = LocalDate.now().minusDays(7);
        return date.isBefore(weekAgo);
    }
    

    Or more leniently, supporting time zones other than Z:

    static boolean isDateOlder(String dateStr) {
        LocalDate date = ZonedDateTime.parse(dateStr.substring(dateStr.indexOf('-') + 1))
                                      .withZoneSameInstant(ZoneId.systemDefault())
                                      .toLocalDate();
        LocalDate weekAgo = LocalDate.now().minusDays(7);
        return date.isBefore(weekAgo);
    }