2

I'm trying to adjust my method and accept current year or next if the second part of date is next year.

My code:

    private static final String PERIOD = "24 Dec-2 Jan";
    private static DateRange _period = null;

    public static void main(final String[] args)
    {
        _period = DateRange.parse(PERIOD, new SimpleDateFormat("dd MMM", Locale.US));
    }

And the parse method:

    public static DateRange parse(final String dateRange, final DateFormat format)
    {
        final String[] date = dateRange.split("-");

        if (date.length == 2)
        {
            try
            {
                final Date startDate = format.parse(date[0]);
                final Date endDate = format.parse(date[1]);

                return new DateRange(startDate, endDate);
            }
            catch (final ParseException e)
            {
                _log.log(Level.WARNING, "Invalid Date Format.", e);
            }
        }

        return new DateRange(null, null);
    }

So after i execute the code i want to have _startDate to show 24 Dec 2020 and _endDate to show 4 JAN 2021 since is in next year

Edit: Current it print this:

Thu Dec 24 00:00:00 EET 1970
Fri Jan 02 00:00:00 EET 1970

While i need this

Thu Dec 24 00:00:00 EET 2020
Fri Jan 02 00:00:00 EET 2021
Frye
  • 21
  • 2
  • So what is wrong with the code you posted? – takendarkk May 11 '20 at 00:17
  • Currently it just parse as it is. Not year. If i system out the startDate it show Sun X X 00:00:00 EET 1970. It was supposed to show Sun X X 00:00:00 EET 2020 and the end date the next year if the month is next year. – Frye May 11 '20 at 00:20

1 Answers1

3

Updated to use Java 8 date APIs. You can find a pre-Java8 version in the revision history.

You can use Java 8 date APIs to parse a MonthDay (a partial date), set it to the current year (with LocalDate), and then adjust the years to move the date range to the earliest valid range in the future.

public static DateRange parse(final String dateRange, final DateTimeFormatter formatter) {
    final String[] dates = dateRange.split("-");
    if (dates.length == 2) {
        try {
            final LocalDate now = LocalDate.now();
            final int currentYear = now.getYear();
            int startYear = currentYear, endYear = currentYear;
            // Parse partial dates (MonthDay) and set the year to the current year.
            LocalDate startDate = MonthDay.parse(dates[0], formatter).atYear(currentYear);
            LocalDate endDate = MonthDay.parse(dates[1], formatter).atYear(currentYear);
            // Increment both years if the start is in the past.
            if (startDate.isBefore(now)) {
                startYear++;
                endYear++;
            }
            // Increment the end year if the end is before the start.
            if (endDate.isBefore(startDate)) {
                endYear++;
            }
            // Update dates with the years.
            startDate = startDate.withYear(startYear);
            endDate = endDate.withYear(endYear);
            return new DateRange(startDate, endDate);
        } catch (DateTimeParseException e) {
            _log.log(Level.WARNING, "Invalid Date Format.", e);
        }
    }
    return null;
}

public static void main(String[] args) {
    final String dateString = "24 Feb-2 Jan";
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMM", Locale.US);
    final DateRange dateRange = parse(dateString, formatter);
    System.out.println(dateRange);
}

Note that the format is d MMM instead of dd MMM to support single digit days.


Alternatively, if you need to support date strings that include years, you can use a LocalDate solution, and add a default year in the formatter parameter.

public static void main(String[] args) {
    final String dateString = "24 Feb-2 Jan";
    final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern("d MMM")
            .parseDefaulting(ChronoField.YEAR, Year.now().getValue())
            .toFormatter(Locale.US);
    final DateRange dateRange = parse(dateString, formatter);
    System.out.println(dateRange);
}

public static DateRange parse(final String dateRange, final DateTimeFormatter formatter) {
    final String[] dates = dateRange.split("-");
    if (dates.length == 2) {
        try {
            final LocalDate now = LocalDate.now();
            final int currentYear = now.getYear();
            int startYear = currentYear, endYear = currentYear;
            // Parse partial dates (MonthDay) and set the year to the current year.
            LocalDate startDate = LocalDate.parse(dates[0], formatter);
            LocalDate endDate = LocalDate.parse(dates[1], formatter);
            // Increment both years if the start is in the past.
            if (startDate.isBefore(now)) {
                startYear++;
                endYear++;
            }
            // Increment the end year if the end is before the start.
            if (endDate.isBefore(startDate)) {
                endYear++;
            }
            // Update dates with the years.
            startDate = startDate.withYear(startYear);
            endDate = endDate.withYear(endYear);
            return new DateRange(startDate, endDate);
        } catch (DateTimeParseException e) {
            _log.log(Level.WARNING, "Invalid Date Format.", e);
        }
    }
    return null;
}
FThompson
  • 28,352
  • 13
  • 60
  • 93
  • You made a small mistake final int endYear = endNextYear ? currentYear + 1 : currentYear; It's the opposite. But aside that your code is working fine thanks a lot. Is there any java 8 less line way to do that? I mean instead of use 15 lines to do in a shorter way? Thats just for me to check libraries and learn. – Frye May 11 '20 at 00:53
  • Good catch; I didn't test the code. As for a better way to do this in Java 8, you should use LocalDate instead of Date. Then, you can use [this](https://stackoverflow.com/a/33700141/1247781) to get the current year and [LocalDate#withYear](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#withYear-int-) instead of Calendar to set the date. – FThompson May 11 '20 at 01:02
  • By the way sir if my current date has passed for example 14 Feb-4 Jan and now we have 11 May which mean it passed i should add +1 year to start date and +1 year to end date am i right? So it will go 14 Feb 2021 - 4 Jan 2022 right sir? – Frye May 11 '20 at 01:20
  • I improved your code a bit and increase by 1 year if date is before now https://pastebin.com/BMXUHZu5 – Frye May 11 '20 at 14:59
  • @Frye Nice work on the improvement. I updated my answer to use Java 8 APIs. It's not fewer lines necessarily but I find the Java 8 version to be much cleaner. You can also use other Java 8 date APIs like [Period](https://docs.oracle.com/javase/8/docs/api/java/time/Period.html) or [Duration](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html) to use the returned date range depending on your use case. Remember to accept the answer if it helps :) – FThompson May 12 '20 at 03:55