user3080698
user3080698

Reputation: 61

Using DateTimeFormatter & LocalDateTime to retrieve day/month/year at hour/minute (Java 1.8)

is using DateTimeFormatter and LocalDateTime best for retrieving a previously set date? If so, how can I implement it into my code (below)?

Update on what I've managed to come up with so far. I think that I more or less know how the date is supposed to work but now I encountered another issue and I am not sure how to solve it so hopefully after posting the code here, I'll be able to get an answer to my problem. In short, I am not sure about a few requirements that I need to implement for my solution to the assignment to work. That's why I'll also post the full requirements below.

Requirements: (In the comment below)

[u](Tests were left out as they can be dealt with later on.)[/u]

Code: Model class [b](Everything to do with assignment was done by me and the rest was already provided)[/b]:

public class Model implements StudentModel {
private ArrayList<Student> students = new ArrayList<>();
private Student currentStudent = null;

private ArrayList<Module> modules = new ArrayList<>();
private Module currentModule;

private ArrayList<Enrolment> enrolments = new ArrayList<>();
private Enrolment currentEnrolment;

private ArrayList<Assignment> assignments = new ArrayList<>();
private Assignment currentAssignment = null;

/**
 * This method is called when the "Add" button in the students data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid create a
 * new Students object. The method will then store the students object for later retrieval.
 *  @param number   is the students identification number
 * @param name of the students
 * @param userId is the students userid / email
 */
@Override
public void addStudent(int number, String name, String userId) {
    Student student = Student.createStudent(number, name, userId, this);
    if (student != null && !foundStudent(student)) {
        this.students.add(student);
        setCurrentStudent(student);
    }
}

/**
 * This method is called when the "Modify" button in the student data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid, it will
 * modify the currently selected Student object. Since this is already in the collection,
 * there is no need to do anything else.
 * @param number is the student identification number
 * @param name of the student
 * @param userId is the students userid / email
 */
public void modifyStudent(int number, String name, String userId) {
    if (currentStudent == null) {
        setErrorMessage("No current student selected");
        return;
    }
    Student student = Student.createStudent(number, name, userId, this);
    if (student != null && (currentStudent.getNumber() == number || !foundStudent(student))) {
        currentStudent.setNumber(number);
        currentStudent.setName(name);
        currentStudent.setUserId(userId);
    }
}

/**
 * This method is called when the "Find" button in the student data panel is clicked. The
 * method should only use values from fields that have been entered. If an object is found
 * then it should be set to the current object.
 *
 * @param number of student to be found
 * @param name of student to be found
 * @param userId is the students userid / email
 * @return true if a student object is found
 */
public boolean findStudent(int number, String name, String userId) {
    setErrorMessage("");
    for (Student student: students) {
        if ((number == 0 || number == student.getNumber()) &&
                (name.equals("") || name.equals(student.getName()))) {
            setCurrentStudent(student);
            return true;
        }
    }
    setErrorMessage("No student object found");
    return false;
}

/**
 * Determine whether the students or the students number already exists in the collection
 *
 * @param student object to be inserted
 * @return true if duplicate students found or students number already used
 */
private boolean foundStudent(Student student) {
    boolean duplicate = false;
    for (Student student1 : students) {
        if (student.equals(student1)) {
            addErrorMessage("Student already in database");
            duplicate = true;
        } else if (student.getNumber() == student1.getNumber()) {
            addErrorMessage("Student number already in database");
            duplicate = true;
        }
    }
    return duplicate;
}

/**
 * This method is called when the user interface wants to know the size of the collection of
 * students.
 *
 * @return an integer value representing the number of students in the collection.
 */
public int getNumberOfStudents() {
    return students.size();
}

/**
 * This method is called when the user interface wants to access members of the collection of
 * Student objects. It provides an index of the item that it wants to retrieve.
 *
 * @param index of item to be retrieved
 * @return a students object
 */
public Student getStudentAt(int index) {
    return students.get(index);
}

/**
 * This method is called when the user interface needs to be able to display
 * information about the currently selected or entered students
 *
 * @return a string with the data for the currently selected students
 */
public Student getCurrentStudent() {
    return currentStudent;
}

/**
 * Retrieves the current student id
 *
 * @return the current student id
 */
public int getStudentNumber() {
    return currentStudent.getNumber();
}

/**
 * Retrieves the current student name
 *
 * @return the current student name
 */
public String getStudentName() {
    return currentStudent.getName();
}

/**
 * Retrieves the current student user id
 *
 * @return the current student user id
 */
public String getStudentUserId() {
    return currentStudent.getUserId();
}

/**
 * This method is called when the user selects a Student in the Student list.
 *
 * @param selectedStudent is reference to the currently selected students object.
 */
public void setCurrentStudent(Student selectedStudent) {
    if (selectedStudent == null) {
        addErrorMessage("This shouldn't be called with a null reference");
        return;
    }
    enrolments = selectedStudent.getEnrolments();
    currentEnrolment = null;
    currentStudent = selectedStudent;
}

/**
 * This method is called when the user clicks the "Delete" button on the Student panel. It
 * should assume that the request is to delete the currently selected student.
 */
public void deleteStudent() {
    if (currentStudent == null) {
        setErrorMessage("No student selected to delete");
        return;
    }
    currentStudent.deleteEnrolments();
    students.remove(currentStudent);
    clearStudent();
}

/**
 * This method should clear the currently selected student.
 */
public void clearStudent() {
    if (currentStudent != null && enrolments == currentStudent.getEnrolments()) {
        enrolments = new ArrayList<>();
        currentEnrolment = null;
    }
    currentStudent = null;
}

/**
 * This method is called when the "Add" button in the currentModule data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid create a
 * new Module object. The method will then store the currentModule object for later retrieval.
 *
 * @param code    of the currentModule
 * @param name    of the currentModule
 * @param credits that the currentModule is worth.
 */
@Override
public void addModule(String code, String name, int credits) {
    Module module = Module.createModule(code, name, credits, this);
    if (module != null && !moduleFound(module)) {
        modules.add(module);
        setCurrentModule(module);
    }
}

/**
 * This method is called when the "Modify" button in the module data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid modify the
 * current Module object.
 *
 * @param code    of the module
 * @param name    of the module
 * @param credits that the module is worth.
 */
public void modifyModule(String code, String name, int credits) {
    if (currentModule == null) {
        setErrorMessage("No current module selected");
        return;
    }
    Module module = Module.createModule(code, name, credits, this);
    if (module != null && (currentModule.getCode().equals(code) || !moduleFound(module))) {
        currentModule.setCode(code);
        currentModule.setName(name);
        currentModule.setCredits(credits);
    }
}

/**
 * This method is called when the "Find" button in the module data panel is clicked. The
 * method should only use values from fields that have been entered. If an object is found
 * then it should be set to the current object.
 *
 * @param code of the module
 * @param name of the module
 * @return true if a module was found and false otherwise
 */
public boolean findModule(String code, String name) {
    setErrorMessage("");
    for (Module module: modules) {
        if ((code.equals("") || code.equals(module.getCode())) &&
                (name.equals("") || name.equals(module.getName())) ||
                (code.equals("") && name.equals(module.getName()))) {
            setCurrentModule(module);
            return true;
        }
    }
    setErrorMessage("No matching module found");
    return false;
}

/**
 * Determine whether this would be a duplicate object or the module code already exists
 *
 * @param module object
 * @return true if module already exists
 */
private boolean moduleFound(Module module) {
    boolean found = false;
    for (Module module1 : modules) {
        if (module.equals(module1)) {
            addErrorMessage("Module already on database");
            found = true;
        } else if (module.getCode().equals(module1.getCode())) {
            addErrorMessage("Module code already on database");
            found = true;
        }
    }
    return found;
}

/**
 * This method is called when the interface needs to know the size of the collection of modules.
 *
 * @return an integer value representing the number of elements in the collection
 */
public int getNumberOfModules() {
    return modules.size();
}

/**
 * This method is called when the user interface wants to access members of the collection of
 * Module objects. It provides an index of the item that it wants to retrieve.
 *
 * @param index of item to be retrieved
 * @return a Module object
 */
public Module getModuleAt(int index) {
    return modules.get(index);
}

/**
 * This method is called when the user clicks the "Delete" button on the Module panel. It
 * should assume that the request is to delete the currently selected Module.
 */
public void deleteModule() {
    if (currentModule == null) {
        setErrorMessage("No module selected to delete");
        return;
    }
    currentModule.deleteEnrolments();
    modules.remove(currentModule);
    clearModule();
}

/**
 * This method should clear the currently selected module.
 */
public void clearModule() {
    if (currentModule != null && enrolments == currentModule.getEnrolments()) {
        enrolments = new ArrayList<>();
        currentEnrolment = null;
    }
    currentModule = null;
}

/**
 * This method is called when the user selects a Module in the Module list.
 *
 * @param selectedValue is a reference to the currently selected Module object.
 */
public void setCurrentModule(Module selectedValue) {
    if (selectedValue == null) {
        addErrorMessage("This shouldn't be called with a null reference");
        return;
    }
    enrolments = selectedValue.getEnrolments();
    currentEnrolment = null;
    currentModule = selectedValue;
}

/**
 * This method is called when the user interface needs to be able to display information
 * about the currently selected or entered currentModule
 *
 * @return the current module
 */
public Module getCurrentModule() {
    return currentModule;
}

/**
 * Retrieves the current module code
 *
 * @return module code for currently selected module
 */
public String getModuleCode() {
    return currentModule.getCode();
}

/**
 * Retrieves the current module name
 *
 * @return module name for currently selected module
 */
public String getModuleName() {
    return currentModule.getName();
}

/**
 * Retrieves the current module credits
 *
 * @return module credits for currently selected module
 */
public int getModuleCredits() {
    return currentModule.getCredits();
}

/**
 * This method is called when the "Add" button in the currentEnrolment data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid create a
 * new Enrolment object. The method will then store the currentEnrolment object for later retrieval.
 * <p/>
 * The students and currentModule data should be those that are currently selected.
 *
 * @param year   of currentEnrolment
 * @param status of the currentEnrolment
 * @param grade  assigned for the currentModule.
 */
@Override
public void addEnrolment(int year, String status, int grade) {
    Enrolment enrolment = Enrolment.createEnrolment(currentStudent, currentModule, year, status,
            grade, this);
    if (enrolment != null && !enrolmentFound(enrolment)) {
        currentStudent.addEnrolment(enrolment);
        currentModule.addEnrolment(enrolment);
        currentEnrolment = enrolment;
    }
}

/**
 * This method is called when the "Modify" button in the enrolment data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid modify the
 * current Enrolment object.
 * <p/>
 * The student and module data should be those that are currently selected.
 *
 * @param year   of enrolment
 * @param status of the enrolment
 * @param grade  assigned for the module.
 */
public void modifyEnrolment(int year, String status, int grade) {
    if (currentEnrolment == null) {
        setErrorMessage("No current enrolment selected");
        return;
    }
    Enrolment enrolment = Enrolment.createEnrolment(currentStudent, currentModule, year, status,
            grade, this);
    if (enrolment != null && (currentEnrolment.equals(enrolment) ||
            !enrolmentFound(enrolment))) {
        currentEnrolment.setStudent(currentStudent);
        currentEnrolment.setModule(currentModule);
        currentEnrolment.setYear(year);
        currentEnrolment.setStatus(status);
        currentEnrolment.setGrade(grade);
    }
}

/**
 * USed to find potentially duplicate modules
 *
 * @param enrolment object
 * @return true if module object with similar values found
 */
private boolean enrolmentFound(Enrolment enrolment) {
    for (Enrolment enrolment1 : enrolments) {
        if (enrolment.equals(enrolment1)) {
            addErrorMessage("Enrolment already in collection");
            return true;
        }
    }
    return false;
}

/**
 * This method is called when the interface needs to know the size of the collection of
 * enrolments.
 *
 * @return an integer value representing the number of elements in the collection
 */
public int getNumberOfEnrolments() {
    return enrolments.size();
}

/**
 * This method is called when the user interface wants to access members of the collection of
 * Enrolment objects. It provides an index of the item that it wants to retrieve.
 *
 * @param index of item to be retrieved
 * @return a Enrolment object
 */
public Enrolment getEnrolmentAt(int index) {
    return enrolments.get(index);
}

/**
 * Obtains the current enrolment
 *
 * @return the current enrolment
 */
public Enrolment getCurrentEnrolment() {
    return currentEnrolment;
}

/**
 * Retrieves the current enrolment year
 *
 * @return year for currently selected enrolment
 */
public int getEnrolmentYear() {
    return currentEnrolment.getYear();
}

/**
 * Retrieves the current enrolment status
 *
 * @return status for currently selected enrolment
 */
public String getEnrolmentStatus() {
    return currentEnrolment.getStatus();
}

/**
 * Retrieves the current enrolment grade
 *
 * @return grade for currently selected enrolment
 */
public int getEnrolmentGrade() {
    return currentEnrolment.getGrade();
}

/**
 * This method is called when the user clicks the "Delete" button on the Enrolment panel. It
 * should assume that the request is to delete the currently selected Enrolment.
 */
public void deleteEnrolment() {
    if (currentEnrolment == null) {
        setErrorMessage("No enrolment selected to delete");
        return;
    }
    currentEnrolment.delete();
    currentEnrolment = null;
}

/**
 * This method should clear the currently selected enrolment.
 */
public void clearEnrolment() {
    currentEnrolment = null;
}

/**
 * This method is called when the user selects an Enrolment in the Enrolment list.
 *
 * @param selectedValue is a reference to the currently selected Enrolment object.
 */
public void setCurrentEnrolment(Enrolment selectedValue) {
    currentEnrolment = selectedValue;
    currentStudent = currentEnrolment.getStudent();
    currentModule = currentEnrolment.getModule();
}



/**
 * This method is called when the "Add" button in the currentAssignment data panel is clicked. The
 * expectation is that the method will validate the data and if the data is valid create a
 * new Assignment object. The method will then store the currentAssignment object for later retrieval.
 *
 * @param title of the assignment
 * @param moduleCode of the assignment
 * @param dateTime is the date on which the assignment has to be handed in
 * @param assignmentPercent weight of the assignment towards the final grade
 *
 */

public void addAssignment(String title, String moduleCode, int assignmentPercent, LocalDateTime dateTime) {
    Assignment assignment = Assignment.createAssignment(title, moduleCode, assignmentPercent, dateTime, this);
    if (assignment != null && !foundAssignment(assignment)) {
        this.assignments.add(assignment);
        setCurrentAssignment(assignment);
    }
}
    /**
     * This method is called when the "Modify" button in the Assignment data panel is clicked. The
     * expectation is that the method will validate the data and if the data is valid, it will
     * modify the currently selected Assignment object. Since this is already in the collection,
     * there is no need to do anything else.
     * @param title of the assignment by which it can be found
     * @param moduleCode contains the module's code
     * @param assignmentPercent weight of the assignment towards the final grade
     */
public void modifyAssignment(String title, String moduleCode, int assignmentPercent, LocalDateTime dateTime) {
    if (currentAssignment == null) {
        setErrorMessage("No current assignment selected");
        return;
    }
    Assignment assignment = Assignment.createAssignment(title, moduleCode, assignmentPercent, dateTime, this );
    if (assignment != null && (currentAssignment.getTitle() == title || !foundAssignment(assignment))) {
        currentAssignment.setTitle(title);
        currentAssignment.setModuleCode(moduleCode);
        currentAssignment.setAssignmentPercent(assignmentPercent);
        currentAssignment.setDueDate(dateTime);
    }
}

/**
 * This method is called when the "Find" button in the Assignment data panel is clicked. The
 * method should only use values from fields that have been entered. If an object is found
 * then it should be set to the current object 'currentAssignment'.
 *
 * @param title of the assignment by which it can be found
 */
public boolean findAssignment(String title) {
    setErrorMessage("");
    for (Assignment assignment: assignments) {
        if (title.equals("") || title.equals(assignment.getTitle())){
            setCurrentAssignment(assignment);
            return true;
        }
    }
    setErrorMessage("No assignment object found");
    return false;
}

/**
 * Determine whether the assignments or the assignment already exists in the database
 *
 * @param assignment object to be inserted
 * @return true if duplicate assignments found or assignment number already used
 */
private boolean foundAssignment(Assignment assignment) {
    boolean found = false;
    for (Assignment assignment1 : assignments) {
        if (assignment.equals(assignment1)) {
            addErrorMessage("Assignment already in database");
            found = true;
        } else if (assignment.getTitle().equals(assignment1.getTitle())) {
            addErrorMessage("Assignment title already in database");
            found = true;
        }
    }
    return found;
}

/**
 * This method is called when the user selects an Assignment in the Assignment list.
 *
 * @param selectedValue is a reference to the currently selected Module object.
 */
public void setCurrentAssignment(Assignment selectedValue) {
    if (selectedValue == null) {
        addErrorMessage("This shouldn't be called with a null reference");
        return;
    }
//        assignments = selectedValue.getAssignments();
//        currentAssignments = null;
//        currentAssignment = selectedValue;
}

/**
 * This method is called when the user interface needs to be able to display information
 * about the currently selected or entered currentAssignment
 *
 * @return the current assignment
 */
public Assignment getCurrentAssignment() {
    return currentAssignment;
}

/**
 * This method should clear the currently selected assignment.
 */
public void clearAssignment() {
    currentAssignment = null;
}

/**
 * Retrieves the current assignment title
 *
 * @return assignment title for currently selected assignment
 */
public String getAssignmentTitle() {
    return currentAssignment.getTitle();
}

/**
 * Retrieves the due date for the assignment
 *
 * @return the due date of the assignment
 */
public int getAssignmentDay() {
    return dateTime.getDayOfMonth();
}

/**
 * Retrieves the month on which the assignment has to be handed in
 *
 * @return due month for currently selected assignment
 */
public String getAssignmentMonth() {
    return currentAssignment.getMonth();
}

/**
 * Retrieves the year on which the assignment has to be handed in
 *
 * @return due year for currently selected assignment
 */
public String getAssignmentYear() {
    return currentAssignment.getYear();
}

/**
 * Retrieves the time on which the assignment has to be handed in
 *
 * @return due hour for currently selected assignment
 */
public String getAssignmentHour() {
    return currentAssignment.getHour();
}

/**
 * Retrieves the time on which the assignment has to be handed in
 *
 * @return due minutes for currently selected assignment
 */
public String getAssignmentMinute() {
    return currentAssignment.getMins();
}
/**
 * Retrieves the weight of the assignment towards the overall grade
 *
 * @return percentage weight for currently selected assignment
 */
public int getAssignmentPercent() {
    return currentModule.getPercentage();
}


/*
 * This block of code is the implementation for the Error Message interface.
 */
private String errorMessage = "";

/**
 * This method simply replaces any message text currently stored with that passed in as a
 * parameter. In effect, it clears past error messages and replaces them with the new message.
 *
 * @param errorMessage is the text of the message to be displayed
 */
public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
}

/**
 * This method appends the new message to the end of any existing error messages inserting
 * the new line sequence between the existing error messages and the new message.
 *
 * @param errorMessage is the text of the message to be displayed
 */
public void addErrorMessage(String errorMessage) {
    this.errorMessage += (this.errorMessage.length() == 0 ? "" : "\n") + errorMessage;
}

/**
 * This method is called by the user interface when it wants to obtain the error messages that
 * are to be displayed.
 *
 * @return the current stored error message
 */
public String getErrorMessage() {
    return errorMessage;
}
}

Upvotes: 1

Views: 704

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 339442

Homework?

For a homework assignment, your instructor may be looking for you to store each component (year, month, hour, and such) as separate numbers for instructional purposes, rather than using date-time classes.

In the real world, you certainly should be using the java.time framework.

Time Zone

And in a real world project, you should know that tracking a date-time without a time zone is asking for trouble.

Technically, a LocalDateTime has no time zone. A LocalDateTime actually has no meaning, and does not represent a moment on the timeline until you apply some timeline to give it meaning. You may assume an intended time zone for a LocalDateTime but that is risky and sloppy. That kind of assumption leads to problems later especially if there were any possible chance of this app later handling such data from another time zone or importing/exporting data from other sources that use other time zones.

UTC

The best practice for date-time work is to use UTC for your business logic, storage, and data exchange. Use a time in a specific time zone only as required such as presentation to a user.

To get to UTC, use your code as-is for parsing into a LocalDateTime. Then apply the time zone for which that value was implicitly assumed. Say, Québec. Apply that time zone, a ZoneId, to produce a ZonedDateTime. Finally, to get to UTC, ask that ZonedDateTime for an Instant.

You can think of it this way conceptually: ZonedDateTime = Instant + ZoneId

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = myLocalDateTime.atZone( zoneId );

From that extract an Instant, a moment on the timeline in UTC. Such Instant instances is what you should use for most business logic and data storage.

Instant instant = zdt.toInstant();

For presentation to a user later, apply the expected/desired time zone.

ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Generating a Formatted String

Use your same formatter to generate a string. Or let java.time localize the format and language for you using a DateTimeFormatter. Specify a Locale which determines (a) the cultural norm for formatting a string, and (b) the translation of the name of day and of month into a particular human language.

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG );
formatter = formatter.withLocale( Locale.CANADA_FRENCH );
String output = zdt.format( formatter );

Example Code

Put it all together.

String input = "29/04/2016 at 23:59";
DateTimeFormatter formatterForParsing = DateTimeFormatter.ofPattern ( "dd/MM/yyyy 'at' HH:mm" );
LocalDateTime ldt = LocalDateTime.parse ( input , formatterForParsing );

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone ( zoneId );
Instant instant = zdt.toInstant ();

// Later, in other code, apply a time zone as required such as presentation to a user.
ZonedDateTime zdtForPresentation = ZonedDateTime.ofInstant ( instant , zoneId );

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.LONG );
formatter = formatter.withLocale ( Locale.CANADA_FRENCH );
String output = zdtForPresentation.format ( formatter );

System.out.println ( "input: " + input + " | ldt: " + ldt + " | zdt: " + zdt + " | instant: " + instant + " | output: " + output );

input: 29/04/2016 at 23:59 | ldt: 2016-04-29T23:59 | zdt: 2016-04-29T23:59-04:00[America/Montreal] | instant: 2016-04-30T03:59:00Z | output: 29 avril 2016 23:59:00 EDT

Half-Open

Another issue… trying to define a due date by the last possible moment is the wrong approach.

In your case of 23:59, you are ignoring that a time-of-day can have a fractional second. In the old date-time classes, that means up to 3 digits of decimal places, 23:59.999. But some databases use microseconds, so 6 digits, 23:59.999999. And now in java.time and some other databases, nanoseconds for 9 digits, 23:59.999999999.

The better approach in date-time work is called Half-Open where the beginning is inclusive and the ending exclusive. So the due date-time is not the last moment of April 29 but the first moment of April 30. The assignment must be received before this first moment of that next day. Just like your attendance in a class at 13:00 requires your derrière be in the seat before 1 PM.

So comparison logic is < rather than <=:

Boolean onTime = whenReceived.isBefore( whenDue );

Poof, your fractional second dilemma is gone.

To get that first moment of the next day, take your ZonedDateTime, add a day, convert to a LocalDate (a date-only value), call atStartOfDay while passing the same time zone again.

ZonedDateTime firstMomentOfNextDay = zdt.plusDays( 1 ).toLocalDate().atStartOfDay( zoneId );

Upvotes: 0

Lucia Pasarin
Lucia Pasarin

Reputation: 2308

My recommendation is to use LocalDateTime only to store the date and not each one of the separate fields that the date is composed of (i.e. day, month, etc.) since you can anytime extract and set all of them.

Using only LocalDateTime you can use both:

public void setDay(int day) {
    dateTime.withDayOfMonth(day);
}

and

public int getDay() {
    return dateTime.getOfMonth();
}

This will then allow you to remove all these fields:

private int day;
private int month;
private int year;
private int hour;
private int minute;

and have a much cleaner constructor:

public Assignment(String title, String moduleCode, int assignmentPercent, LocalDateTime dateTime) {
    // ...
}

Upvotes: 1

Related Questions