1

I have a Task object that has a name and a date. The date value must be a String. An example is 11/9/2015 23:00 to be compared to 11/24/2015 12:00. I need help writing a compareTo() for this so that the task with the soonest date is displayed first. What I have is incorrect as it does not compare correctly. I know there are alternatives but it is required I do this with String. I have considered using .split() to break up mm/dd/yyyy by "/" but not sure how to do this.

public class Task implements Comparable<Task> {
    /** Task name. */
    private String name;
    /** Task due date. */
    private String dueDate;

    /**
     * Initializes a tasks name and due date.
     * @param n Name
     * @param d due date
     */
    public Task(String n, String d) {
        name = n;
        dueDate = d;
    }

    /**
     * Accessor for task name.
     * @return Task name.
     */
    public String getName() {
        return name;
    }

    /**
     * Accessor for task due date.
     * @return Task due date.
     */
    public String getDueDate() {
        return dueDate;
    }

    /**
     * Compares the due dates of the tasks to get the soonest to the front of the list.
     * @param t The task to compare.
     * @return The tasks in chronological order.
     */
    @Override
    public int compareTo(Task t) { //Need help here.
        int val = dueDate.compareTo(t.getDueDate());

        if(val == 0) {
            val = name.compareTo(t.getName());
        }
        if(dueDate.compareTo(t.getDueDate()) > 0) {
            val = -1;
        }
        if(dueDate.compareTo(t.getDueDate()) < 0) {
            val = 1;
        }   
        return val;
    }
Mureinik
  • 297,002
  • 52
  • 306
  • 350
JCCS
  • 591
  • 8
  • 22
  • can you convert to a Date object and then compare? – AbtPst Nov 04 '15 at 20:57
  • Possible duplicate of [Comparing date strings in Java](http://stackoverflow.com/questions/10609596/comparing-date-strings-in-java) – Alex Shesterov Nov 04 '15 at 20:59
  • @AbtPst No i must just use `String` – JCCS Nov 04 '15 at 20:59
  • @AlexShesterov Not quite a duplicate, as this Question is about date-time while your link is about date-only. Here is another near-duplicate but date-only: [How to get date in string and compare it using java](http://stackoverflow.com/q/14065633/642706). – Basil Bourque Nov 04 '15 at 21:48
  • Can you explain why you *must* use a String instead of a Date? – Tom Nov 04 '15 at 22:12

2 Answers2

2

The fact that you have to have the date as a string doesn't mean you can't convert it to a Date and use that class' natural ordering:

@Override
public int compareTo(Task t) {
    // Handling ParseExceptions omitted for bravity's sake
    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm");
    Date d1 = df.parse(dueDate);
    Date d2 = df.parse(t.getDueDate());

    int val = d1.compareTo(d2);

    if(val != 0) {
        return val;    
    }
    return name.compareTo(t.getName());
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
1

Date-Time Objects

I suggest you use date-time objects rather than strings as members in your class.

Java 8 and later includes the very useful java.time framework. Use these new classes (inspired by Joda-Time) rather than the notoriously troublesome old classes, java.util.Date/.Calendar.

No need to parse the date-time input strings. The java.time framework by default parses any string in ISO 8601 format. For other formats, define a formatter pattern of your expected inputs, and let java.time do the work.

Time Zone

You cannot compare such date-time strings as yours without knowing their time zone. Perhaps it is UTC? Or do you assume all your data refers to a specific time zone?

In example below, I arbitrarily assume a time zone of America/Los_Angeles.

Example code.

This example code in Java 8 uses the java.time.format package to parse your string for input in the constructor and again to generate a String representation in the dueDateTimeAsAmericaLosAngeles method.

Generally best to keep date-time values in UTC time zone. Then adjust to a time zone when expected by the user or by other software. So we store an Instant on the class, a moment on the timeline in UTC. For specific time zones, create a ZonedDateTime object.

If, against my advice, you insist on storing the date-time value as a string then you can modify this code by moving around where the string parsing-to-Instant happens.

package timestuff;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Task implements Comparable<Task> {

    String title;
    Instant due;

    public Task ( String title , String dateTimeAssumedToBeAmericaLosAngles ) {
        this.title = title;
        ZoneId zoneId = ZoneId.of ( "America/Los_Angeles" );
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "M/d/yyyy HH:mm" ).withZone ( zoneId ); // Example data: 11/24/2015 12:00
        this.due = formatter.parse ( dateTimeAssumedToBeAmericaLosAngles , Instant :: from );
    }

    @Override
    public String toString () {
        return "Task{ " + "title=" + title + " | instant=" + due + " }";
    }

    @Override
    public int compareTo ( Task t ) {
        // Sort by the date-time of when this task is due.
        int result = this.due.compareTo ( t.due );
        return result;
    }

    String dueDateTimeAsAmericaLosAngeles () {
        ZoneId zoneId = ZoneId.of ( "America/Los_Angeles" );
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "M/d/yyyy HH:mm" ).withZone ( zoneId ); // Example data: 11/24/2015 12:00
        ZonedDateTime zdt = ZonedDateTime.ofInstant ( this.due , zoneId );
        String output = zdt.format ( formatter );
        return output;
    }

    public static void main ( String[] args ) {
        Task t1 = new Task ( "x" , "11/9/2015 23:00" );
        Task t2 = new Task ( "y" , "11/24/2015 12:00" );
        int compared = t1.compareTo ( t2 );
        System.out.println ( "t1: " + t1 + " & t2: " + t2 + " compared: " + compared );
    }

}

When run:

t1: Task{ title=x | instant=2015-11-10T07:00:00Z } & t2: Task{ title=y | instant=2015-11-24T20:00:00Z } compared: -1

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154