0

I have problem which can't solve. The user is asked to input a date and it's compared to todays date and if it's in the future the user is asked to input date again. The first time it works and tells user it's in the future but when he enters a valid date it's still showing to re-enter. Any help appreciated.

    System.out.println("Purchase date DD/MM/YYYY:");
    String date = sc.nextLine();
    SimpleDateFormat dateform = new SimpleDateFormat ("DD/MM/YYYY");
    dateform.parse(date);
    Date d = new Date();
    Date d2 = dateform.parse(date);
    while (d2.compareTo(d) > 0 ){
        
        System.out.println("Re-enter");
        date = sc.nextLine();   
    }
    consumbles.add(date);
Arvind Kumar Avinash
  • 50,121
  • 5
  • 26
  • 72
warren89
  • 21
  • 4
  • Change `while (...) {...}` into a `do {...} while (...);` – Hovercraft Full Of Eels Mar 13 '21 at 12:27
  • 1
    you can use LocalDate and for date pattern string : dd/MM/yyyy – JHDev Mar 13 '21 at 12:28
  • Yes I tried it too but it seems that the entered valid date is not being read because it keeps saying to re-enter – warren89 Mar 13 '21 at 12:33
  • Please also look at [Scanner is skipping nextLine() after using next(), nextInt() or other nextFoo() methods](http://stackoverflow.com/questions/13102045/scanner-is-skipping-nextline-after-using-next-nextint-or-other-nextfoo) as this may have bearing on your question or problem. If still stuck, consider creating and posting a valid [mre]. The link will explain what this is and how it can help you and us. – Hovercraft Full Of Eels Mar 13 '21 at 12:39
  • System.out.println("Purchase date DD/MM/YYYY:"); String date = sc.nextLine(); SimpleDateFormat dateform = new SimpleDateFormat ("DD/MM/YYYY"); dateform.parse(date); Date d = new Date(); Date d2 = dateform.parse(date); do { System.out.println("Re-enter"); date=sc.nextLine(); } while (d2.compareTo(d) > 0 ); " I tried the do while loop and it works but the problem is same as before whereas when the user re-enters the date and is valid it's keeping saYING TO re-enter – warren89 Mar 13 '21 at 12:51
  • 1
    Please no code in comments, and please no information key to understanding the question in comments as both items belong within the question proper. Please [edit] and improve the question, and then notify us of the updates in comments. – Hovercraft Full Of Eels Mar 13 '21 at 13:00
  • @warren89, you can use this code : Scanner sc = new Scanner(System.in); LocalDate entredDate = null; LocalDate nowDate = LocalDate.now(); do { System.out.println("Purchase date DD/MM/YYYY:"); String date = sc.nextLine(); DateTimeFormatter dateform = DateTimeFormatter.ofPattern("dd/MM/yyyy"); entredDate = LocalDate.parse(date, dateform); nowDate = LocalDate.now(); }while (nowDate.isBefore(entredDate) ); – JHDev Mar 13 '21 at 13:04
  • I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `LocalDate` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Mar 13 '21 at 13:05
  • Are you changing `d2` or `d1` inside the loop? If not, do you still expect `d2.compareTo(d) > 0` to yield a different result the next time through? – Ole V.V. Mar 13 '21 at 13:07
  • I added *Java iterator.hasNext() is always true* as an original question. This one may not be a very exact duplicate of that one, but I am still hoping that the similarity is great enough that the link could be helpful. – Ole V.V. Mar 13 '21 at 13:58
  • @OleV.V. The aim is to compare the entered date with the current date and the user must enter current date or past date but not future one. in my code I'm using the same variable used the first time the user enters a date – warren89 Mar 13 '21 at 13:59
  • @warren89 Yes. And it’s called *variable* because you can assign a new value to it. As long as you don’t do that, it keeps its original value. – Ole V.V. Mar 13 '21 at 14:01
  • You need to have ``d2 = dateform.parse(date);`` inside the while-loop body. – NomadMaker Mar 13 '21 at 15:06

2 Answers2

4
    System.out.println("Purchase date DD/MM/YYYY:");
    String date = sc.nextLine();
    // Use java.time, the modern Java date and time API, for your date work.
    // Use single letters in the format pattern string to allow user
    // to enter single digit day and month.
    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("d/M/u");
    // Use saying variable names (not just d and d2)
    LocalDate today = LocalDate.now(ZoneId.systemDefault());
    LocalDate dateEntered = LocalDate.parse(date, dateFormatter);
    // Using isAfter() for comparison is easier to read then compareTo()
    while (dateEntered.isAfter(today)) {
        System.out.println("Re-enter");
        date = sc.nextLine();
        // Parse the new entered date string into dateEntered
        dateEntered = LocalDate.parse(date, dateFormatter);
    }

    System.out.println("You have successfully entered " + dateEntered);

Sample session:

Purchase date DD/MM/YYYY:
15/3/2021
Re-enter
11/3/2021
You have successfully entered 2021-03-11

Your errors were:

  • You were using the wrong case of pattern letters in your format pattern string. No matter if using the old and troublesome SimpleDateFormat or the modern DateTimeFormatter pattern letters are case sensitive. Upper case D is for day of year, lowercase d for day of month. Upper case Y is for week year and only useful with a week number. Lowercase y is for year of era. In my code I used lower case u for a signed year, this is special for DateTimeFormatter.
  • You were not assigning a new value to d2 when the user entered a new date. Thus when your condition, d2.compareTo(d) > 0, was true, it would stay true no matter how many times the user entered a different date.
Ole V.V.
  • 65,573
  • 11
  • 96
  • 117
1

You can use a variable (e.g. boolean valid in the code below) to track whether the input is valid. If the input is not valid, you need to loop back. I prefer using do-while loop, which guarantees to execute its body at least once, for such a scenario. I also recommend you handle exception for invalid input.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws ParseException {
        Scanner sc = new Scanner(System.in);
        SimpleDateFormat parser = new SimpleDateFormat("d/M/yyyy", Locale.ENGLISH);
        Date today = new Date();
        boolean valid;

        do {
            valid = true;
            System.out.print("Purchase date DD/MM/YYYY: ");
            String strDate = sc.nextLine();
            Date date = null;

            try {
                date = parser.parse(strDate);
                if (date.after(today)) {
                    System.out.println("The date should not be a future date. Please try again.");
                    valid = false;
                }
            } catch (ParseException e) {
                System.out.println("Invalid date/format. Please try again.");
                valid = false;
            }
        } while (!valid);

        System.out.println("Thank you! Processing ...");
    }
}

A sample run:

Purchase date DD/MM/YYYY: a
Invalid date/format. Please try again.
Purchase date DD/MM/YYYY: 14/3/2021
The date should not be a future date. Please try again.
Purchase date DD/MM/YYYY: 12/2/2020
Thank you! Processing ...

Note that the java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API*.

Using the modern date-time API:

import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("d/M/u", Locale.ENGLISH);
        LocalDate today = LocalDate.now();
        boolean valid;

        do {
            valid = true;
            System.out.print("Purchase date DD/MM/YYYY: ");
            String strDate = sc.nextLine();
            LocalDate date = null;
            try {
                date = LocalDate.parse(strDate, parser);
                if (date.isAfter(today)) {
                    System.out.println("The date should not be a future date. Please try again.");
                    valid = false;
                }
            } catch (DateTimeException e) {
                System.out.println("Invalid date/format. Please try again.");
                valid = false;
            }
        } while (!valid);

        System.out.println("Thank you! Processing ...");
    }
}

Learn more about the modern date-time API from Trail: Date Time.

Note:

  1. You have wrongly used D instead of d. D is used for Day in year, not for Day in month.
  2. You have wrongly used Y instead of y. Y is used for a Week year, not for year.

* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 50,121
  • 5
  • 26
  • 72