-7

I get two strings and I must transform them into dates and show the difference in days between them. But I must throw an exception if one of the two dates is invalid.

This is the code I have so far for this task:

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String d1 = sc.next();
        String d2 = sc.next();

        SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");

        try {
            Date date1 = formatter.parse(d1);
            Date date2 = formatter.parse(d2);

            long dt = (date1.getTime() - date2.getTime()) + 3600000;
            long days = (dt / 86400000L);

            System.out.println(days);
        } catch (ParseException e) {
            System.out.println("Data inválida");
            e.printStackTrace();
        }
    }
}

But if I enter an invalid date like 02/29/2021, it converts to 03/01/2021 instead of throwing the exception.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • Try `formatter.setLenient(false);` – shmosel Oct 25 '21 at 21:02
  • 4
    You shouldn't use `Date` and `SimpleDateFormat`, they're both obsolete. Use classes from the `java.time` package instead. In your case probably `LocalDate`. Then with `ChronoUnit.DAYS.between(date1, date2)` you got the time in between. – MC Emperor Oct 25 '21 at 21:13
  • @shmosel it worked, thanks – Robson Fischer Oct 25 '21 at 21:17
  • 1
    @MCEmperor how i can change my formatter to use LocalDate? – Robson Fischer Oct 25 '21 at 21:19
  • 1
    https://stackoverflow.com/questions/27005861/calculate-days-between-two-dates-in-java-8 – shmosel Oct 25 '21 at 21:22
  • Always search Stack Overflow thoroughly before posting. This topic has been addressed many many times already. – Basil Bourque Oct 25 '21 at 22:19
  • Does this answer your question? [SimpleDateFormat parse in wrong date for 29 February \[duplicate\]](https://stackoverflow.com/questions/68042689/simpledateformat-parse-in-wrong-date-for-29-february). Does [this](https://stackoverflow.com/questions/1905551/make-simpledateformat-parse-fail-on-invalid-dates-e-g-month-is-greater-than)? – Ole V.V. Oct 26 '21 at 09:12

1 Answers1

2

java.time

@MCEmperor how i can change my formatter to use LocalDate?

Like MCEmperor I recommend that you use java.time, the modern Java date and time API, for your date work.

public class Main {
    private static final DateTimeFormatter FORMATTER
            = DateTimeFormatter.ofPattern("dd/MM/uuuu", Locale.ROOT)
                    .withResolverStyle(ResolverStyle.STRICT);

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String d1 = sc.next();
        String d2 = sc.next();
        
        try {
            LocalDate date1 = LocalDate.parse(d1, FORMATTER);
            LocalDate date2 = LocalDate.parse(d2, FORMATTER);
            
            long days = ChronoUnit.DAYS.between(date2, date1);
            
            System.out.println(days);
        } catch (DateTimeParseException dtpe) {
            System.out.println("Data inválida");
            dtpe.printStackTrace();
        }
    }
}

Example session:

03/02/2021
02/29/2021
Data inválida
java.time.format.DateTimeParseException: Text '02/29/2021' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 29
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.LocalDate.parse(LocalDate.java:428)
    at Main.main(Main.java:18)

You may also notice in the code how much more natural and simple it is to calculate the number of days between the two dates.

What went wrong in your code?

But if I enter an invalid date like 02/29/2021, it converts to 03/01/2021 instead of throwing the exception.

That’s as designed. And I agree with you, it’s a confusing, surprising and unfortunate design. When you pass February 29 in a non-leap year to a SimpleDateFormat with default settings, it just takes it as the day after February 28, that is, March 1. It’s just one of very many reasons not to use that class.

Link

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

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    Good suggestions! However, I would use `Scanner#nextLine` instead of `Scanner#next`. Though not required for this particular pattern, imagine the requirement changes to deal with patterns like `MM dd yyyy` or `EEE dd MMM` etc. – Arvind Kumar Avinash Oct 27 '21 at 18:32
  • 1
    Yes, @ArvindKumarAvinash, me too. :-) In this case I took over uncritically from the question to make it easier to distinguish which changes would be *necessary* for migrating to java.time. – Ole V.V. Oct 27 '21 at 19:37