[英]Using DateTimeFormatter & LocalDateTime to retrieve day/month/year at hour/minute (Java 1.8)
最好使用DateTimeFormatter和LocalDateTime来检索先前设置的日期? 如果是这样,如何将其实现到我的代码中(如下)?
什么我已经成功更新拿出这么远。 我想我或多或少知道日期应该如何工作,但是现在我遇到了另一个问题,我不确定如何解决它,因此希望在将代码发布到这里后,我将能够得到我问题的答案。 。 简而言之,对于执行工作分配的解决方案,我不确定需要实现哪些要求。 这就是为什么我还将在下面发布全部要求。
要求:( 在下面的评论中)
[u](测试被省略,因为以后可以处理。)[/ u]
代码:模型类[b](与分配有关的所有工作均由我完成,其余工作已提供)[/ 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;
}
}
我的建议是仅使用LocalDateTime来存储日期,而不使用日期组成的每个单独字段(例如,日,月等),因为您可以随时提取并设置所有这些字段。
仅使用LocalDateTime可以同时使用以下两者:
public void setDay(int day) {
dateTime.withDayOfMonth(day);
}
和
public int getDay() {
return dateTime.getOfMonth();
}
然后,您可以删除所有这些字段:
private int day;
private int month;
private int year;
private int hour;
private int minute;
并有一个更干净的构造函数:
public Assignment(String title, String moduleCode, int assignmentPercent, LocalDateTime dateTime) {
// ...
}
对于家庭作业,您的讲师可能正在寻找您将每个组件(年,月,小时等)存储为单独的数字,以用于指导目的,而不是使用日期时间类。
在现实世界中,您当然应该使用java.time框架。
在现实世界的项目中,您应该知道,跟踪没有时区的日期时间会带来麻烦。
从技术上讲, LocalDateTime
没有时区。 LocalDateTime
实际上没有任何意义,并且在您应用某些时间轴赋予其含义之前不会在时间轴上表示时刻。 您可能会为LocalDateTime
假定一个预期的时区,但这既冒险又草率。 那种假设导致了问题以后,特别是如果有这样的应用程序以后从另一个时区处理这些数据或导入/从使用其他时区的其他来源的数据导出任何可能的机会。
日期时间工作的最佳实践是将UTC用于业务逻辑,存储和数据交换。 仅在需要时才使用特定时区中的时间,例如向用户演示。
要使用UTC,请按原样使用代码解析为LocalDateTime
。 然后应用隐含假定该值的时区。 说, 魁北克 。 应用该时区ZoneId
来产生ZonedDateTime
。 最后,要到达UTC,请向ZonedDateTime
发出Instant
。
您可以从概念上这样思考: ZonedDateTime
= Instant
+ ZoneId
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = myLocalDateTime.atZone( zoneId );
从中提取一个Instant
,在UTC时间轴上的一个时刻。 对于大多数业务逻辑和数据存储,应使用此类Instant
实例。
Instant instant = zdt.toInstant();
为了稍后显示给用户,请应用期望/期望的时区。
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
使用相同的格式化程序生成字符串。 或者让java.time使用DateTimeFormatter
为您本地化格式和语言。 指定一个Locale
,该Locale
确定(a)用于格式化字符串的文化规范,以及(b)将“ day”和“ month”的名称翻译成特定的人类语言。
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG );
formatter = formatter.withLocale( Locale.CANADA_FRENCH );
String output = zdt.format( formatter );
全部放在一起。
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 );
输入:2016年4月29日在23:59 | ldt:2016-04-29T23:59 | zdt:2016-04-29T23:59-04:00 [美国/蒙特利尔] | 即时:2016-04-30T03:59:00Z | 输出:2016年4月29日美国东部时间
另一个问题……试图在可能的最后时刻定义到期日期是错误的方法。
在23:59
的情况下,您忽略了一天中的时间可能只有一小数秒。 在旧的日期时间类中,这意味着最多3位小数点,即23:59.999
。 但是某些数据库使用微秒,因此6位数字23:59.999999
。 现在在java.time和其他一些数据库中,9位数为纳秒, 23:59.999999999
。
在日期时间工作中,更好的方法称为Half-Open ,其中开始是包含在内的 ,结尾是排他的 。 因此,到期日期时间不是4月29日的最后时刻,而是4月30日的第一时刻。必须在第二天的第一时刻之前收到分配。 就像您在13:00上课一样,您的derrière必须在下午1点之前坐在座位上。
因此比较逻辑是<
而不是<=
:
Boolean onTime = whenReceived.isBefore( whenDue );
of ,您的第二个难题陷入了困境。
要获得第二天的第一刻,请使用ZonedDateTime
,添加一天,转换为LocalDate
(仅日期的值),在再次传递相同时区的同时调用atStartOfDay
。
ZonedDateTime firstMomentOfNextDay = zdt.plusDays( 1 ).toLocalDate().atStartOfDay( zoneId );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.