Java class that does calculations between dates
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
4
down vote
favorite
I am writing a simple java class for date calculations, I am aware there are probably better ones out there, but I want to do this myself for practicing purposes. I am planning on expanding this class but I am posting this here mainly because this is the first time I am doing something OOP related and the first time I am using java as well and I want some feedback.
package oop;
public class Date
private String hour = null;
private String minute = null;
private String second = null;
private String day = null;
private String month = null;
private String year = null;
private String meridiem = null;
public Date(String hour, String minute, String second, String meridiem)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
public Date(String day, String month, String year)
this.day = day;
this.month = month;
this.year = year;
public Date(String hour, String minute, String second, String meridiem, String day, String month, String year)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
this.day = day;
this.month = month;
this.year = year;
public String concatenateDate()
String fullDate = "";
if(hour != null)
fullDate += hour + ":" + minute + ":" + second;
if(day != null)
if(hour != null) fullDate += " ";
fullDate += day + "/" + month + "/" + year;
return fullDate;
public int daysUntilNextYear()
int nextYear = 0;
int daysLeft = -1;
System.out.println(year != null);
if(year != null)
daysLeft = daysDistance(new Date("01", "01", Integer.toString(Integer.parseInt(year)+1)));
return daysLeft;
private int getDaysGone(int day, int month, int year)
int daysGone = day;
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
if(isLeapYear(year) && month > 2)
daysGone ++;
return daysGone;
private boolean isLeapYear(int year)
if(year%400 == 0
public int daysDistance(Date secondDate)
int daysDistance = 0;
try
int year = Integer.parseInt(this.year);
int month = Integer.parseInt(this.month);
int day = Integer.parseInt(this.day);
int secondYear = Integer.parseInt(secondDate.getYear());
int secondMonth = Integer.parseInt(secondDate.getMonth());
int secondDay = Integer.parseInt(secondDate.getDay());
daysDistance += (secondYear - year) * 365;
daysDistance += (getDaysGone(secondDay, secondMonth, secondYear) - getDaysGone(day, month, year) -1);
daysDistance = Math.abs(daysDistance);
if(secondYear > year)
for(int i = year+1; i < secondYear; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month < 3) daysDistance++;
if(isLeapYear(secondYear) && secondMonth > 3) daysDistance++;
else if(secondYear == year)
if(secondMonth > month)
if(isLeapYear(year) && month < 3 && secondMonth > 3) daysDistance ++;
else
if(isLeapYear(year) && month > 3 && secondMonth < 3) daysDistance ++;
else
for(int i = secondYear+1; i < year; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month > 3) daysDistance ++;
if(isLeapYear(secondYear) && secondMonth < 3) daysDistance++;
catch(Exception e)
daysDistance = -1;
return daysDistance;
public int secondsUntilDate(Date secondDate)
int secondsLeft = 0;
try
secondsLeft += (daysDistance(secondDate)) * 86400;
secondsLeft += 86400 - (Integer.parseInt(hour)*3600 + Integer.parseInt(second)) ;
catch(Exception e)
secondsLeft = -1;
return secondsLeft;
public String getDay()
return day;
public String getMonth()
return month;
public String getYear()
return year;
public String getHour()
return hour;
public String getMinute()
return minute;
public String getSecond()
return second;
public String getMeridiem()
return meridiem;
java beginner object-oriented datetime
add a comment |Â
up vote
4
down vote
favorite
I am writing a simple java class for date calculations, I am aware there are probably better ones out there, but I want to do this myself for practicing purposes. I am planning on expanding this class but I am posting this here mainly because this is the first time I am doing something OOP related and the first time I am using java as well and I want some feedback.
package oop;
public class Date
private String hour = null;
private String minute = null;
private String second = null;
private String day = null;
private String month = null;
private String year = null;
private String meridiem = null;
public Date(String hour, String minute, String second, String meridiem)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
public Date(String day, String month, String year)
this.day = day;
this.month = month;
this.year = year;
public Date(String hour, String minute, String second, String meridiem, String day, String month, String year)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
this.day = day;
this.month = month;
this.year = year;
public String concatenateDate()
String fullDate = "";
if(hour != null)
fullDate += hour + ":" + minute + ":" + second;
if(day != null)
if(hour != null) fullDate += " ";
fullDate += day + "/" + month + "/" + year;
return fullDate;
public int daysUntilNextYear()
int nextYear = 0;
int daysLeft = -1;
System.out.println(year != null);
if(year != null)
daysLeft = daysDistance(new Date("01", "01", Integer.toString(Integer.parseInt(year)+1)));
return daysLeft;
private int getDaysGone(int day, int month, int year)
int daysGone = day;
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
if(isLeapYear(year) && month > 2)
daysGone ++;
return daysGone;
private boolean isLeapYear(int year)
if(year%400 == 0
public int daysDistance(Date secondDate)
int daysDistance = 0;
try
int year = Integer.parseInt(this.year);
int month = Integer.parseInt(this.month);
int day = Integer.parseInt(this.day);
int secondYear = Integer.parseInt(secondDate.getYear());
int secondMonth = Integer.parseInt(secondDate.getMonth());
int secondDay = Integer.parseInt(secondDate.getDay());
daysDistance += (secondYear - year) * 365;
daysDistance += (getDaysGone(secondDay, secondMonth, secondYear) - getDaysGone(day, month, year) -1);
daysDistance = Math.abs(daysDistance);
if(secondYear > year)
for(int i = year+1; i < secondYear; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month < 3) daysDistance++;
if(isLeapYear(secondYear) && secondMonth > 3) daysDistance++;
else if(secondYear == year)
if(secondMonth > month)
if(isLeapYear(year) && month < 3 && secondMonth > 3) daysDistance ++;
else
if(isLeapYear(year) && month > 3 && secondMonth < 3) daysDistance ++;
else
for(int i = secondYear+1; i < year; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month > 3) daysDistance ++;
if(isLeapYear(secondYear) && secondMonth < 3) daysDistance++;
catch(Exception e)
daysDistance = -1;
return daysDistance;
public int secondsUntilDate(Date secondDate)
int secondsLeft = 0;
try
secondsLeft += (daysDistance(secondDate)) * 86400;
secondsLeft += 86400 - (Integer.parseInt(hour)*3600 + Integer.parseInt(second)) ;
catch(Exception e)
secondsLeft = -1;
return secondsLeft;
public String getDay()
return day;
public String getMonth()
return month;
public String getYear()
return year;
public String getHour()
return hour;
public String getMinute()
return minute;
public String getSecond()
return second;
public String getMeridiem()
return meridiem;
java beginner object-oriented datetime
1
Welcome to Code Review. While this is fine as an exercise, I would highly recommend not to write your own date-time types for production code usage, as there is a huge amount of room for error (time zones, leap years/seconds, and so on). I recommend reading this Oracle article for more details.
â Phrancis
Jun 8 at 4:20
right now only has one method???
â Sharon Ben Asher
Jun 8 at 12:01
add a comment |Â
up vote
4
down vote
favorite
up vote
4
down vote
favorite
I am writing a simple java class for date calculations, I am aware there are probably better ones out there, but I want to do this myself for practicing purposes. I am planning on expanding this class but I am posting this here mainly because this is the first time I am doing something OOP related and the first time I am using java as well and I want some feedback.
package oop;
public class Date
private String hour = null;
private String minute = null;
private String second = null;
private String day = null;
private String month = null;
private String year = null;
private String meridiem = null;
public Date(String hour, String minute, String second, String meridiem)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
public Date(String day, String month, String year)
this.day = day;
this.month = month;
this.year = year;
public Date(String hour, String minute, String second, String meridiem, String day, String month, String year)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
this.day = day;
this.month = month;
this.year = year;
public String concatenateDate()
String fullDate = "";
if(hour != null)
fullDate += hour + ":" + minute + ":" + second;
if(day != null)
if(hour != null) fullDate += " ";
fullDate += day + "/" + month + "/" + year;
return fullDate;
public int daysUntilNextYear()
int nextYear = 0;
int daysLeft = -1;
System.out.println(year != null);
if(year != null)
daysLeft = daysDistance(new Date("01", "01", Integer.toString(Integer.parseInt(year)+1)));
return daysLeft;
private int getDaysGone(int day, int month, int year)
int daysGone = day;
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
if(isLeapYear(year) && month > 2)
daysGone ++;
return daysGone;
private boolean isLeapYear(int year)
if(year%400 == 0
public int daysDistance(Date secondDate)
int daysDistance = 0;
try
int year = Integer.parseInt(this.year);
int month = Integer.parseInt(this.month);
int day = Integer.parseInt(this.day);
int secondYear = Integer.parseInt(secondDate.getYear());
int secondMonth = Integer.parseInt(secondDate.getMonth());
int secondDay = Integer.parseInt(secondDate.getDay());
daysDistance += (secondYear - year) * 365;
daysDistance += (getDaysGone(secondDay, secondMonth, secondYear) - getDaysGone(day, month, year) -1);
daysDistance = Math.abs(daysDistance);
if(secondYear > year)
for(int i = year+1; i < secondYear; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month < 3) daysDistance++;
if(isLeapYear(secondYear) && secondMonth > 3) daysDistance++;
else if(secondYear == year)
if(secondMonth > month)
if(isLeapYear(year) && month < 3 && secondMonth > 3) daysDistance ++;
else
if(isLeapYear(year) && month > 3 && secondMonth < 3) daysDistance ++;
else
for(int i = secondYear+1; i < year; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month > 3) daysDistance ++;
if(isLeapYear(secondYear) && secondMonth < 3) daysDistance++;
catch(Exception e)
daysDistance = -1;
return daysDistance;
public int secondsUntilDate(Date secondDate)
int secondsLeft = 0;
try
secondsLeft += (daysDistance(secondDate)) * 86400;
secondsLeft += 86400 - (Integer.parseInt(hour)*3600 + Integer.parseInt(second)) ;
catch(Exception e)
secondsLeft = -1;
return secondsLeft;
public String getDay()
return day;
public String getMonth()
return month;
public String getYear()
return year;
public String getHour()
return hour;
public String getMinute()
return minute;
public String getSecond()
return second;
public String getMeridiem()
return meridiem;
java beginner object-oriented datetime
I am writing a simple java class for date calculations, I am aware there are probably better ones out there, but I want to do this myself for practicing purposes. I am planning on expanding this class but I am posting this here mainly because this is the first time I am doing something OOP related and the first time I am using java as well and I want some feedback.
package oop;
public class Date
private String hour = null;
private String minute = null;
private String second = null;
private String day = null;
private String month = null;
private String year = null;
private String meridiem = null;
public Date(String hour, String minute, String second, String meridiem)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
public Date(String day, String month, String year)
this.day = day;
this.month = month;
this.year = year;
public Date(String hour, String minute, String second, String meridiem, String day, String month, String year)
this.hour = hour;
this.minute = minute;
this.second = second;
this.meridiem = meridiem;
this.day = day;
this.month = month;
this.year = year;
public String concatenateDate()
String fullDate = "";
if(hour != null)
fullDate += hour + ":" + minute + ":" + second;
if(day != null)
if(hour != null) fullDate += " ";
fullDate += day + "/" + month + "/" + year;
return fullDate;
public int daysUntilNextYear()
int nextYear = 0;
int daysLeft = -1;
System.out.println(year != null);
if(year != null)
daysLeft = daysDistance(new Date("01", "01", Integer.toString(Integer.parseInt(year)+1)));
return daysLeft;
private int getDaysGone(int day, int month, int year)
int daysGone = day;
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
if(isLeapYear(year) && month > 2)
daysGone ++;
return daysGone;
private boolean isLeapYear(int year)
if(year%400 == 0
public int daysDistance(Date secondDate)
int daysDistance = 0;
try
int year = Integer.parseInt(this.year);
int month = Integer.parseInt(this.month);
int day = Integer.parseInt(this.day);
int secondYear = Integer.parseInt(secondDate.getYear());
int secondMonth = Integer.parseInt(secondDate.getMonth());
int secondDay = Integer.parseInt(secondDate.getDay());
daysDistance += (secondYear - year) * 365;
daysDistance += (getDaysGone(secondDay, secondMonth, secondYear) - getDaysGone(day, month, year) -1);
daysDistance = Math.abs(daysDistance);
if(secondYear > year)
for(int i = year+1; i < secondYear; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month < 3) daysDistance++;
if(isLeapYear(secondYear) && secondMonth > 3) daysDistance++;
else if(secondYear == year)
if(secondMonth > month)
if(isLeapYear(year) && month < 3 && secondMonth > 3) daysDistance ++;
else
if(isLeapYear(year) && month > 3 && secondMonth < 3) daysDistance ++;
else
for(int i = secondYear+1; i < year; i++)
if(isLeapYear(i))
daysDistance ++;
if(isLeapYear(year) && month > 3) daysDistance ++;
if(isLeapYear(secondYear) && secondMonth < 3) daysDistance++;
catch(Exception e)
daysDistance = -1;
return daysDistance;
public int secondsUntilDate(Date secondDate)
int secondsLeft = 0;
try
secondsLeft += (daysDistance(secondDate)) * 86400;
secondsLeft += 86400 - (Integer.parseInt(hour)*3600 + Integer.parseInt(second)) ;
catch(Exception e)
secondsLeft = -1;
return secondsLeft;
public String getDay()
return day;
public String getMonth()
return month;
public String getYear()
return year;
public String getHour()
return hour;
public String getMinute()
return minute;
public String getSecond()
return second;
public String getMeridiem()
return meridiem;
java beginner object-oriented datetime
edited Jun 8 at 14:33
asked Jun 8 at 1:54
Just Half
212
212
1
Welcome to Code Review. While this is fine as an exercise, I would highly recommend not to write your own date-time types for production code usage, as there is a huge amount of room for error (time zones, leap years/seconds, and so on). I recommend reading this Oracle article for more details.
â Phrancis
Jun 8 at 4:20
right now only has one method???
â Sharon Ben Asher
Jun 8 at 12:01
add a comment |Â
1
Welcome to Code Review. While this is fine as an exercise, I would highly recommend not to write your own date-time types for production code usage, as there is a huge amount of room for error (time zones, leap years/seconds, and so on). I recommend reading this Oracle article for more details.
â Phrancis
Jun 8 at 4:20
right now only has one method???
â Sharon Ben Asher
Jun 8 at 12:01
1
1
Welcome to Code Review. While this is fine as an exercise, I would highly recommend not to write your own date-time types for production code usage, as there is a huge amount of room for error (time zones, leap years/seconds, and so on). I recommend reading this Oracle article for more details.
â Phrancis
Jun 8 at 4:20
Welcome to Code Review. While this is fine as an exercise, I would highly recommend not to write your own date-time types for production code usage, as there is a huge amount of room for error (time zones, leap years/seconds, and so on). I recommend reading this Oracle article for more details.
â Phrancis
Jun 8 at 4:20
right now only has one method???
â Sharon Ben Asher
Jun 8 at 12:01
right now only has one method???
â Sharon Ben Asher
Jun 8 at 12:01
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
1
down vote
why is your instance variables defined as
String
? it makes no sense. it allows user of your class to pass invalid values and it forces you to parse into int in several places. (and you should know thatparseInt()
may throw an exception if the value is not numeric). it makes much more sense to have the variables defined as int.you should validate your input. months are between 1 and 12 and days should be validated according to the given month. you can either throw a custom checked exception (to force clients to catch it), or use the JDK unchecked
IllegalArgumentException
constructor overloading: you have 3 constructors. one that is a combination of the other two. If you want to follow the DRY rule, then you probably want to make private methods like
setTime(...)
andsetDate(...)
. then have each constructor call the approperiate method and the 7 arg constructor will call both. The methods is the place where you will want to perform validation as well.7 arg constructor, all args of the same type - that's going to be a problem for your users. they have no idea of the order of args (unless you provide extensive javadoc documentation, which you didn't). A good fit here is the Builder pattern that allows the construction of object that require many args and/or configuration. so your user can do:
Date today = new Date().withYear(2018).withMonth(6).withDayOfMonth(8);
avoid magic numbers. use constants. instead of
86400
defineprivate static final int SECONDS_IN_DAY
(and assign it a multiplication ofSECONDS_IN_HOUR
) this makes the code more readable and you also support other planets in our solar system.getDaysGone()
- now wouldn't it be more useful to have a map of months and their respective number of days? this will help in validation as wellwhat about daylight saving?
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
add a comment |Â
up vote
1
down vote
I think the first thing you should do is defining the Date interface which lists all functionalities then implement it effectively by your way. You should not implement first and then think to born some useful functions. You can read Java Calendar to know more what they did and what they provided.
add a comment |Â
up vote
0
down vote
Note that it took years and years to get to the new Java date / time API. Stephen Colebourne wrote the Joda-Time API before heading the new API team. Time is an obnoxiously hard nut to crack. If this is an assignment then the date / time subject is probably chosen on purpose: it will generate an endless number of irregularities that can be useful for teaching.
There are several time-based standards, e.g. an ISO norm that specifies how UTC needs to behave and how to format canonical UTC based dates. If you would implement this for a company then you should:
- lookup the standards and
- find a matching implementation for keeping time.
Then you should not write wrapper classes around an existing API for generic operations: only create use-case specific classes and methods where required.
The Date
class in Java itself uses milliseconds from 1970. This makes it easy to perform calculations, while you can still convert back to local time (using the badly named and implemented Calendar
class).
This should also protect you from weird situations where the day
(of month) is set, but the month isn't: you just choose the first day of month if it is not present.
In other words: it protects your class instances from ever reaching an invalid state. Avoiding invalid states is very important from a security and maintainability perspective. It is one of the reasons why immutable classes are often preferred as, internally, they can only have a single state (a point in time). These classes don't have setters, instead they require that you call methods to create new instances, e.g. nextDay(): Date
.
One of the principles for defensive programming is called fail-fast where you immediately throw an exception instead of having to deal with invalid state. Validating the parameters of your constructors is an important first step to create a fail-fast implementation.
I would highly recommend to have a look at "Effective Java" from Joshua Bloch and then take a look at the new Java time API to see how it is implemented.
Code specific comments
Meridian (meridiem
?) isn't really used in the class or in the calculations. As long as this is not the case, you should leave it out because your calculations should take it into account. Meridians aren't used in time calculations that use local time; the time zone and daylight saving may be.
Instead of constructors without specific names it is better to use factory methods, e.g. createDate(int year, int month, int dayOfMonth): Date
. This makes it immediately clear what the arguments are.
Instead of returning -1
for daysUntilNextYear()
you should make your class in such a way that it cannot return a bad value for the method.
Currently you are deferring the handling of the issue to the user of the class. That means that the user needs to implement a condition, throwing an Exception
when -1
is returned. Even worse, if this is forgotten then the user will end up with a bad calculation result. That means that the error is propagated in a different, hard to catch form!
If you keep to the current design then you could either throw an Exception
yourself or return an Optional<Integer>
value. But these are both band-aid solutions.
if(year%400 == 0 || (year%100 != 0 && year%4 == 0 ))
return true;
else
return false;
Ah, my young Padawan, here you show your inexperience:
return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0 )
also: do keep the spaces for readability. Can you see the difference?
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
It isn't often the case but here a switch with fall-thru is probably a good idea.
switch (month)
case 12:
daysGone += 31;
// fall-thru (to next case)
case 11:
daysGone += 30:
// fall-thru
case 2:
// do something special here for special years
default:
throw new RuntimeException("Unknown month: " + month);
using a constant such as public static final int DECEMBER = 12
would make your code more readable:
case DECEMBER:
daysGone += 31;
// fall-thru (to next case)
It would also allow your users to reuse your constant. In modern Java you could use an enum
with a method getCommonDays
for the month (with Common
to allow for February) but it may be a bit early to go into that.
getDaysGone
should use isLeapYear
for February than requiring that you adjust the date later.
It's unclear from the method what concatenateDate(): String
does. You could create a method called readableDate()
instead. You could also implement / override the toString()
method for debugging.
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
why is your instance variables defined as
String
? it makes no sense. it allows user of your class to pass invalid values and it forces you to parse into int in several places. (and you should know thatparseInt()
may throw an exception if the value is not numeric). it makes much more sense to have the variables defined as int.you should validate your input. months are between 1 and 12 and days should be validated according to the given month. you can either throw a custom checked exception (to force clients to catch it), or use the JDK unchecked
IllegalArgumentException
constructor overloading: you have 3 constructors. one that is a combination of the other two. If you want to follow the DRY rule, then you probably want to make private methods like
setTime(...)
andsetDate(...)
. then have each constructor call the approperiate method and the 7 arg constructor will call both. The methods is the place where you will want to perform validation as well.7 arg constructor, all args of the same type - that's going to be a problem for your users. they have no idea of the order of args (unless you provide extensive javadoc documentation, which you didn't). A good fit here is the Builder pattern that allows the construction of object that require many args and/or configuration. so your user can do:
Date today = new Date().withYear(2018).withMonth(6).withDayOfMonth(8);
avoid magic numbers. use constants. instead of
86400
defineprivate static final int SECONDS_IN_DAY
(and assign it a multiplication ofSECONDS_IN_HOUR
) this makes the code more readable and you also support other planets in our solar system.getDaysGone()
- now wouldn't it be more useful to have a map of months and their respective number of days? this will help in validation as wellwhat about daylight saving?
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
add a comment |Â
up vote
1
down vote
why is your instance variables defined as
String
? it makes no sense. it allows user of your class to pass invalid values and it forces you to parse into int in several places. (and you should know thatparseInt()
may throw an exception if the value is not numeric). it makes much more sense to have the variables defined as int.you should validate your input. months are between 1 and 12 and days should be validated according to the given month. you can either throw a custom checked exception (to force clients to catch it), or use the JDK unchecked
IllegalArgumentException
constructor overloading: you have 3 constructors. one that is a combination of the other two. If you want to follow the DRY rule, then you probably want to make private methods like
setTime(...)
andsetDate(...)
. then have each constructor call the approperiate method and the 7 arg constructor will call both. The methods is the place where you will want to perform validation as well.7 arg constructor, all args of the same type - that's going to be a problem for your users. they have no idea of the order of args (unless you provide extensive javadoc documentation, which you didn't). A good fit here is the Builder pattern that allows the construction of object that require many args and/or configuration. so your user can do:
Date today = new Date().withYear(2018).withMonth(6).withDayOfMonth(8);
avoid magic numbers. use constants. instead of
86400
defineprivate static final int SECONDS_IN_DAY
(and assign it a multiplication ofSECONDS_IN_HOUR
) this makes the code more readable and you also support other planets in our solar system.getDaysGone()
- now wouldn't it be more useful to have a map of months and their respective number of days? this will help in validation as wellwhat about daylight saving?
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
add a comment |Â
up vote
1
down vote
up vote
1
down vote
why is your instance variables defined as
String
? it makes no sense. it allows user of your class to pass invalid values and it forces you to parse into int in several places. (and you should know thatparseInt()
may throw an exception if the value is not numeric). it makes much more sense to have the variables defined as int.you should validate your input. months are between 1 and 12 and days should be validated according to the given month. you can either throw a custom checked exception (to force clients to catch it), or use the JDK unchecked
IllegalArgumentException
constructor overloading: you have 3 constructors. one that is a combination of the other two. If you want to follow the DRY rule, then you probably want to make private methods like
setTime(...)
andsetDate(...)
. then have each constructor call the approperiate method and the 7 arg constructor will call both. The methods is the place where you will want to perform validation as well.7 arg constructor, all args of the same type - that's going to be a problem for your users. they have no idea of the order of args (unless you provide extensive javadoc documentation, which you didn't). A good fit here is the Builder pattern that allows the construction of object that require many args and/or configuration. so your user can do:
Date today = new Date().withYear(2018).withMonth(6).withDayOfMonth(8);
avoid magic numbers. use constants. instead of
86400
defineprivate static final int SECONDS_IN_DAY
(and assign it a multiplication ofSECONDS_IN_HOUR
) this makes the code more readable and you also support other planets in our solar system.getDaysGone()
- now wouldn't it be more useful to have a map of months and their respective number of days? this will help in validation as wellwhat about daylight saving?
why is your instance variables defined as
String
? it makes no sense. it allows user of your class to pass invalid values and it forces you to parse into int in several places. (and you should know thatparseInt()
may throw an exception if the value is not numeric). it makes much more sense to have the variables defined as int.you should validate your input. months are between 1 and 12 and days should be validated according to the given month. you can either throw a custom checked exception (to force clients to catch it), or use the JDK unchecked
IllegalArgumentException
constructor overloading: you have 3 constructors. one that is a combination of the other two. If you want to follow the DRY rule, then you probably want to make private methods like
setTime(...)
andsetDate(...)
. then have each constructor call the approperiate method and the 7 arg constructor will call both. The methods is the place where you will want to perform validation as well.7 arg constructor, all args of the same type - that's going to be a problem for your users. they have no idea of the order of args (unless you provide extensive javadoc documentation, which you didn't). A good fit here is the Builder pattern that allows the construction of object that require many args and/or configuration. so your user can do:
Date today = new Date().withYear(2018).withMonth(6).withDayOfMonth(8);
avoid magic numbers. use constants. instead of
86400
defineprivate static final int SECONDS_IN_DAY
(and assign it a multiplication ofSECONDS_IN_HOUR
) this makes the code more readable and you also support other planets in our solar system.getDaysGone()
- now wouldn't it be more useful to have a map of months and their respective number of days? this will help in validation as wellwhat about daylight saving?
answered Jun 8 at 12:57
Sharon Ben Asher
2,038512
2,038512
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
add a comment |Â
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
What would I do if in the setTime(. . .) and setDate(. . .) methods the validation returns false? How do I stop everything from there and notify the user that something went wrong?
â Just Half
Jun 8 at 15:02
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
throw an exception
â Sharon Ben Asher
Jun 8 at 16:31
add a comment |Â
up vote
1
down vote
I think the first thing you should do is defining the Date interface which lists all functionalities then implement it effectively by your way. You should not implement first and then think to born some useful functions. You can read Java Calendar to know more what they did and what they provided.
add a comment |Â
up vote
1
down vote
I think the first thing you should do is defining the Date interface which lists all functionalities then implement it effectively by your way. You should not implement first and then think to born some useful functions. You can read Java Calendar to know more what they did and what they provided.
add a comment |Â
up vote
1
down vote
up vote
1
down vote
I think the first thing you should do is defining the Date interface which lists all functionalities then implement it effectively by your way. You should not implement first and then think to born some useful functions. You can read Java Calendar to know more what they did and what they provided.
I think the first thing you should do is defining the Date interface which lists all functionalities then implement it effectively by your way. You should not implement first and then think to born some useful functions. You can read Java Calendar to know more what they did and what they provided.
answered Jun 9 at 8:35
huuthang
111
111
add a comment |Â
add a comment |Â
up vote
0
down vote
Note that it took years and years to get to the new Java date / time API. Stephen Colebourne wrote the Joda-Time API before heading the new API team. Time is an obnoxiously hard nut to crack. If this is an assignment then the date / time subject is probably chosen on purpose: it will generate an endless number of irregularities that can be useful for teaching.
There are several time-based standards, e.g. an ISO norm that specifies how UTC needs to behave and how to format canonical UTC based dates. If you would implement this for a company then you should:
- lookup the standards and
- find a matching implementation for keeping time.
Then you should not write wrapper classes around an existing API for generic operations: only create use-case specific classes and methods where required.
The Date
class in Java itself uses milliseconds from 1970. This makes it easy to perform calculations, while you can still convert back to local time (using the badly named and implemented Calendar
class).
This should also protect you from weird situations where the day
(of month) is set, but the month isn't: you just choose the first day of month if it is not present.
In other words: it protects your class instances from ever reaching an invalid state. Avoiding invalid states is very important from a security and maintainability perspective. It is one of the reasons why immutable classes are often preferred as, internally, they can only have a single state (a point in time). These classes don't have setters, instead they require that you call methods to create new instances, e.g. nextDay(): Date
.
One of the principles for defensive programming is called fail-fast where you immediately throw an exception instead of having to deal with invalid state. Validating the parameters of your constructors is an important first step to create a fail-fast implementation.
I would highly recommend to have a look at "Effective Java" from Joshua Bloch and then take a look at the new Java time API to see how it is implemented.
Code specific comments
Meridian (meridiem
?) isn't really used in the class or in the calculations. As long as this is not the case, you should leave it out because your calculations should take it into account. Meridians aren't used in time calculations that use local time; the time zone and daylight saving may be.
Instead of constructors without specific names it is better to use factory methods, e.g. createDate(int year, int month, int dayOfMonth): Date
. This makes it immediately clear what the arguments are.
Instead of returning -1
for daysUntilNextYear()
you should make your class in such a way that it cannot return a bad value for the method.
Currently you are deferring the handling of the issue to the user of the class. That means that the user needs to implement a condition, throwing an Exception
when -1
is returned. Even worse, if this is forgotten then the user will end up with a bad calculation result. That means that the error is propagated in a different, hard to catch form!
If you keep to the current design then you could either throw an Exception
yourself or return an Optional<Integer>
value. But these are both band-aid solutions.
if(year%400 == 0 || (year%100 != 0 && year%4 == 0 ))
return true;
else
return false;
Ah, my young Padawan, here you show your inexperience:
return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0 )
also: do keep the spaces for readability. Can you see the difference?
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
It isn't often the case but here a switch with fall-thru is probably a good idea.
switch (month)
case 12:
daysGone += 31;
// fall-thru (to next case)
case 11:
daysGone += 30:
// fall-thru
case 2:
// do something special here for special years
default:
throw new RuntimeException("Unknown month: " + month);
using a constant such as public static final int DECEMBER = 12
would make your code more readable:
case DECEMBER:
daysGone += 31;
// fall-thru (to next case)
It would also allow your users to reuse your constant. In modern Java you could use an enum
with a method getCommonDays
for the month (with Common
to allow for February) but it may be a bit early to go into that.
getDaysGone
should use isLeapYear
for February than requiring that you adjust the date later.
It's unclear from the method what concatenateDate(): String
does. You could create a method called readableDate()
instead. You could also implement / override the toString()
method for debugging.
add a comment |Â
up vote
0
down vote
Note that it took years and years to get to the new Java date / time API. Stephen Colebourne wrote the Joda-Time API before heading the new API team. Time is an obnoxiously hard nut to crack. If this is an assignment then the date / time subject is probably chosen on purpose: it will generate an endless number of irregularities that can be useful for teaching.
There are several time-based standards, e.g. an ISO norm that specifies how UTC needs to behave and how to format canonical UTC based dates. If you would implement this for a company then you should:
- lookup the standards and
- find a matching implementation for keeping time.
Then you should not write wrapper classes around an existing API for generic operations: only create use-case specific classes and methods where required.
The Date
class in Java itself uses milliseconds from 1970. This makes it easy to perform calculations, while you can still convert back to local time (using the badly named and implemented Calendar
class).
This should also protect you from weird situations where the day
(of month) is set, but the month isn't: you just choose the first day of month if it is not present.
In other words: it protects your class instances from ever reaching an invalid state. Avoiding invalid states is very important from a security and maintainability perspective. It is one of the reasons why immutable classes are often preferred as, internally, they can only have a single state (a point in time). These classes don't have setters, instead they require that you call methods to create new instances, e.g. nextDay(): Date
.
One of the principles for defensive programming is called fail-fast where you immediately throw an exception instead of having to deal with invalid state. Validating the parameters of your constructors is an important first step to create a fail-fast implementation.
I would highly recommend to have a look at "Effective Java" from Joshua Bloch and then take a look at the new Java time API to see how it is implemented.
Code specific comments
Meridian (meridiem
?) isn't really used in the class or in the calculations. As long as this is not the case, you should leave it out because your calculations should take it into account. Meridians aren't used in time calculations that use local time; the time zone and daylight saving may be.
Instead of constructors without specific names it is better to use factory methods, e.g. createDate(int year, int month, int dayOfMonth): Date
. This makes it immediately clear what the arguments are.
Instead of returning -1
for daysUntilNextYear()
you should make your class in such a way that it cannot return a bad value for the method.
Currently you are deferring the handling of the issue to the user of the class. That means that the user needs to implement a condition, throwing an Exception
when -1
is returned. Even worse, if this is forgotten then the user will end up with a bad calculation result. That means that the error is propagated in a different, hard to catch form!
If you keep to the current design then you could either throw an Exception
yourself or return an Optional<Integer>
value. But these are both band-aid solutions.
if(year%400 == 0 || (year%100 != 0 && year%4 == 0 ))
return true;
else
return false;
Ah, my young Padawan, here you show your inexperience:
return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0 )
also: do keep the spaces for readability. Can you see the difference?
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
It isn't often the case but here a switch with fall-thru is probably a good idea.
switch (month)
case 12:
daysGone += 31;
// fall-thru (to next case)
case 11:
daysGone += 30:
// fall-thru
case 2:
// do something special here for special years
default:
throw new RuntimeException("Unknown month: " + month);
using a constant such as public static final int DECEMBER = 12
would make your code more readable:
case DECEMBER:
daysGone += 31;
// fall-thru (to next case)
It would also allow your users to reuse your constant. In modern Java you could use an enum
with a method getCommonDays
for the month (with Common
to allow for February) but it may be a bit early to go into that.
getDaysGone
should use isLeapYear
for February than requiring that you adjust the date later.
It's unclear from the method what concatenateDate(): String
does. You could create a method called readableDate()
instead. You could also implement / override the toString()
method for debugging.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
Note that it took years and years to get to the new Java date / time API. Stephen Colebourne wrote the Joda-Time API before heading the new API team. Time is an obnoxiously hard nut to crack. If this is an assignment then the date / time subject is probably chosen on purpose: it will generate an endless number of irregularities that can be useful for teaching.
There are several time-based standards, e.g. an ISO norm that specifies how UTC needs to behave and how to format canonical UTC based dates. If you would implement this for a company then you should:
- lookup the standards and
- find a matching implementation for keeping time.
Then you should not write wrapper classes around an existing API for generic operations: only create use-case specific classes and methods where required.
The Date
class in Java itself uses milliseconds from 1970. This makes it easy to perform calculations, while you can still convert back to local time (using the badly named and implemented Calendar
class).
This should also protect you from weird situations where the day
(of month) is set, but the month isn't: you just choose the first day of month if it is not present.
In other words: it protects your class instances from ever reaching an invalid state. Avoiding invalid states is very important from a security and maintainability perspective. It is one of the reasons why immutable classes are often preferred as, internally, they can only have a single state (a point in time). These classes don't have setters, instead they require that you call methods to create new instances, e.g. nextDay(): Date
.
One of the principles for defensive programming is called fail-fast where you immediately throw an exception instead of having to deal with invalid state. Validating the parameters of your constructors is an important first step to create a fail-fast implementation.
I would highly recommend to have a look at "Effective Java" from Joshua Bloch and then take a look at the new Java time API to see how it is implemented.
Code specific comments
Meridian (meridiem
?) isn't really used in the class or in the calculations. As long as this is not the case, you should leave it out because your calculations should take it into account. Meridians aren't used in time calculations that use local time; the time zone and daylight saving may be.
Instead of constructors without specific names it is better to use factory methods, e.g. createDate(int year, int month, int dayOfMonth): Date
. This makes it immediately clear what the arguments are.
Instead of returning -1
for daysUntilNextYear()
you should make your class in such a way that it cannot return a bad value for the method.
Currently you are deferring the handling of the issue to the user of the class. That means that the user needs to implement a condition, throwing an Exception
when -1
is returned. Even worse, if this is forgotten then the user will end up with a bad calculation result. That means that the error is propagated in a different, hard to catch form!
If you keep to the current design then you could either throw an Exception
yourself or return an Optional<Integer>
value. But these are both band-aid solutions.
if(year%400 == 0 || (year%100 != 0 && year%4 == 0 ))
return true;
else
return false;
Ah, my young Padawan, here you show your inexperience:
return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0 )
also: do keep the spaces for readability. Can you see the difference?
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
It isn't often the case but here a switch with fall-thru is probably a good idea.
switch (month)
case 12:
daysGone += 31;
// fall-thru (to next case)
case 11:
daysGone += 30:
// fall-thru
case 2:
// do something special here for special years
default:
throw new RuntimeException("Unknown month: " + month);
using a constant such as public static final int DECEMBER = 12
would make your code more readable:
case DECEMBER:
daysGone += 31;
// fall-thru (to next case)
It would also allow your users to reuse your constant. In modern Java you could use an enum
with a method getCommonDays
for the month (with Common
to allow for February) but it may be a bit early to go into that.
getDaysGone
should use isLeapYear
for February than requiring that you adjust the date later.
It's unclear from the method what concatenateDate(): String
does. You could create a method called readableDate()
instead. You could also implement / override the toString()
method for debugging.
Note that it took years and years to get to the new Java date / time API. Stephen Colebourne wrote the Joda-Time API before heading the new API team. Time is an obnoxiously hard nut to crack. If this is an assignment then the date / time subject is probably chosen on purpose: it will generate an endless number of irregularities that can be useful for teaching.
There are several time-based standards, e.g. an ISO norm that specifies how UTC needs to behave and how to format canonical UTC based dates. If you would implement this for a company then you should:
- lookup the standards and
- find a matching implementation for keeping time.
Then you should not write wrapper classes around an existing API for generic operations: only create use-case specific classes and methods where required.
The Date
class in Java itself uses milliseconds from 1970. This makes it easy to perform calculations, while you can still convert back to local time (using the badly named and implemented Calendar
class).
This should also protect you from weird situations where the day
(of month) is set, but the month isn't: you just choose the first day of month if it is not present.
In other words: it protects your class instances from ever reaching an invalid state. Avoiding invalid states is very important from a security and maintainability perspective. It is one of the reasons why immutable classes are often preferred as, internally, they can only have a single state (a point in time). These classes don't have setters, instead they require that you call methods to create new instances, e.g. nextDay(): Date
.
One of the principles for defensive programming is called fail-fast where you immediately throw an exception instead of having to deal with invalid state. Validating the parameters of your constructors is an important first step to create a fail-fast implementation.
I would highly recommend to have a look at "Effective Java" from Joshua Bloch and then take a look at the new Java time API to see how it is implemented.
Code specific comments
Meridian (meridiem
?) isn't really used in the class or in the calculations. As long as this is not the case, you should leave it out because your calculations should take it into account. Meridians aren't used in time calculations that use local time; the time zone and daylight saving may be.
Instead of constructors without specific names it is better to use factory methods, e.g. createDate(int year, int month, int dayOfMonth): Date
. This makes it immediately clear what the arguments are.
Instead of returning -1
for daysUntilNextYear()
you should make your class in such a way that it cannot return a bad value for the method.
Currently you are deferring the handling of the issue to the user of the class. That means that the user needs to implement a condition, throwing an Exception
when -1
is returned. Even worse, if this is forgotten then the user will end up with a bad calculation result. That means that the error is propagated in a different, hard to catch form!
If you keep to the current design then you could either throw an Exception
yourself or return an Optional<Integer>
value. But these are both band-aid solutions.
if(year%400 == 0 || (year%100 != 0 && year%4 == 0 ))
return true;
else
return false;
Ah, my young Padawan, here you show your inexperience:
return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0 )
also: do keep the spaces for readability. Can you see the difference?
if(month == 2) daysGone += 31;
else if(month == 3) daysGone += 59;
else if(month == 4) daysGone += 90;
else if(month == 5) daysGone += 120;
else if(month == 6) daysGone += 151;
else if(month == 7)daysGone += 181;
else if(month == 8)daysGone += 212;
else if(month == 9)daysGone += 243;
else if(month == 10) daysGone +=273;
else if(month == 11)daysGone += 304;
else if(month == 12)daysGone += 334;
It isn't often the case but here a switch with fall-thru is probably a good idea.
switch (month)
case 12:
daysGone += 31;
// fall-thru (to next case)
case 11:
daysGone += 30:
// fall-thru
case 2:
// do something special here for special years
default:
throw new RuntimeException("Unknown month: " + month);
using a constant such as public static final int DECEMBER = 12
would make your code more readable:
case DECEMBER:
daysGone += 31;
// fall-thru (to next case)
It would also allow your users to reuse your constant. In modern Java you could use an enum
with a method getCommonDays
for the month (with Common
to allow for February) but it may be a bit early to go into that.
getDaysGone
should use isLeapYear
for February than requiring that you adjust the date later.
It's unclear from the method what concatenateDate(): String
does. You could create a method called readableDate()
instead. You could also implement / override the toString()
method for debugging.
edited Jun 8 at 14:50
answered Jun 8 at 14:05
Maarten Bodewes
417211
417211
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f196081%2fjava-class-that-does-calculations-between-dates%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
Welcome to Code Review. While this is fine as an exercise, I would highly recommend not to write your own date-time types for production code usage, as there is a huge amount of room for error (time zones, leap years/seconds, and so on). I recommend reading this Oracle article for more details.
â Phrancis
Jun 8 at 4:20
right now only has one method???
â Sharon Ben Asher
Jun 8 at 12:01