Which method should I use? - java

I'm an intermediate java coder, writing a librarian Java app, and for some reason I just can't figure out whether I should use dueDate.after(today) OR dueDate.before(today) method as to deciding if the book is overdue. I've gotten quite some contradictory values by typing both the methods. Hence, I'm also assuming there is some other bug in my code as well, so it would be nice if you can conform which is the correct method so that I can move on the fixing the other bug.

You need dueDate.before(today): the due date is before today; the due date is in the past, so the book is past due.
Maybe it's easier if you swap the objects around? You'd get today.after(dueDate) and if you read that out loud, it suddenly becomes quite clear: "if today is after the due date, then ..."

Remember that the before and after methods perform a < (or >) comparison, rather than a <= (or >= comparison). That is what is meant by the word "strictly" in the API documentation.
Also, Java Date objects are really an instant in time, rather than what people usually think of as a "date". That is, it won't just compare the day, but the time of day.
If you want to compare only the day, without checking the time during that day, create all of your due dates to be at a specific time, like midnight. For example, suppose that a book is due October 26. The due date could be midnight, October 27.
boolean overdue = !now.before(dueDate);
The somewhat awkward negation accounts for the case when it is now exactly 12:00 AM Oct. 27.

dueDate.before(today) would translate to the actual dueDate of the book occurring before today, meaning that it is actually overdue. This is probably what you want (assuming you are checking for true)
the other side of things
dueDate.after(today) would translate to the actual dueDate of the book occurring after today, meaning that it is not yet over due.

The only difference between !dueDate.after(today) and dueDate.before(today) is the result when both dates are exactly the same - presumably a book is not overdue when returned on the due date, so dueDate.before(today) should be correct.
As for your unspecified other problems: are you aware that java.util.Date represents a millisecond-precision point in time, not a calendar date? That means that in order to use its comparison methods for calendar dates, you have to make very sure you set the time components to zero when creating your Date instances. Another cause of problems could be time zone differences.

It depends on what you want to achieve. Is dueDate the date you want to set when lending a book? The due date is derived from the lending date of the book, so I would try an approach like book.isDue(today) assuming that the book object contains the lending and due dates as attributes.
With questions like this it helps if you make it explicit for yourself which objects are involved and what their relations are before you design the actions between the objects.

Related

Best way to store time in java, in format of HH:MM

After doing my research I wasn't able to find a method or data type that should be used for variable in order to store time in format of HH:MM, I did find methods to get this from a string like "14:15:10", but I think this is not the best way, as I'll need to add or subtract from time. I tried doing this as a double, but ran into following issue, when you have a time like 05.45 stored and add 0.15 (or 15 minutes) to it, the result is 05.60 where as with HH:MM format you'd expect it to be 06.00.
I'm looked through java documentation and still am, but can't seem to find any way to achieve this, closest I got to is date format like dd/mm/yyyy hh:mm:ss
Use Joda Time. It provides much better operations to do date/time manipulation than standard java dates. If you want to use internal JDK classes, use java.util.Date.
Since Java 8, you can use the new API for dates and times, including Instant, ZonedDateTime and LocalDateTime. This removes the use for the third party library Joda time. It also makes calculations more easy and correct. The advice below is a bit dated but still has some good points.
—————
What you definitely should NOT do is store them in your own custom format. Store the Long value that represents the Unix Epoch.
A DateTime is nothing more than a number to a computer. This number represents the amount of seconds (or milliseconds) since 1970-01-01 00:00:00 UTC. It's beyond the scope of this answer to explain why this date was universally chosen but you can find this by searching for Unix Epoch or reading http://en.wikipedia.org/wiki/Unix_time.
This also means there is NO timezone information stored in a DateTime itself. It is important to keep this in mind when reasoning about dates and times. For things such as comparing DateTime objects, nothing concerning localization or timezones is done. Only when formatting time, which means as much as making it readable to humans, or for operations such as getting the beginning of the day, timezones come into play.
This is also why you shouldn't store the time like 20:11:15 in a string-like format because this information is meaningless without timezone information. I will give you 1 example here: Consider the moment when the clock is moved back 1 hour, such as when moving away from daylight savings time. It just happened in a lot of countries. What does your string 02:30 represent? The first or the second one?
Calculations such as subtraction are as easy as doing the same with numbers. For example: Date newDate = new Date(date1.getTime() - date2.getTime());. Or want to add an hour to a date? Date newDate = new Date(oldDate.getTime() + 1000 * 60 * 60);
If you need more complex stuff then using Joda time would be a good idea, as was already suggested. But it's perfectly possible to just do even that with the native libraries too.
If there's one resource that taught me a lot about date/time, it would be http://www.odi.ch/prog/design/datetime.php
Java has java.sql.Time format to work with time-of-day values. Just import it and create variables.
import java.sql.Time;
//now we can make time variables
Time myTime;
Just saw it on https://db.apache.org/derby/docs/10.4/ref/rrefsqlj21908.html
The answer that is right for your case depends on what you want to do.
Are you using a RDBMS as your persistence engine?
If so, are you already working with legacy data formats or are you building a database from the ground up?
Are you simply storing this data, or will you be doing extensive date arithmetic and/or precedence calculations?
Are you in one time zone or do you need to work with time instants across many time zones?
All of these things are important and factor into your decision of how to represent your times and dates.
If your needs require a lot of date arithmetic (eg. determining days between dates) or sorting based on timestamps, then consider using a floating point date format. The advantage of using a numeric format for timestamps is that doing date arithmetic and comparison/sorting operations becomes trivial; you merely do simple arithmetic. Another advantage is that floats and longs are primitive data types. They do not need to be serialized, they are already extremely lightweight, and everything you need to use them requires no external dependencies.
The main disadvantage to using numeric formats for timestamps is that they are not human friendly. You'll need to convert them to and from a String format to allow users to interact. Oftentimes, this is worth the effort. See: How do I use Julian Day Numbers with the Java Calendar API?
I recommend that you consider storing timestamps as Julian Day Numbers (JDNs) or Modified Julian Day Numbers (MJDs). Both will represent dates and times to millisecond precision using an 8 byte float. Algorithms for converting to and from display formats for both of these are highly standardized. They confer all the advantages of using numeric dates. Moreover, they are defined only for GMT/UTC which means that your timestamps are already universalizable across time zones right out of the box (as long as you localize properly).
If you dont want the full date object, your best bet is to store it in a string, but I personally would still recommend date as it also contains a lot of convenient methods that will come in handy. You can just get the time as a whole from a date object and ignore the rest.
In terms of "storing" a date, you should use a long. This is how the system sees it and how all calculations are performed. Yes, as some point out you will eventually need to create a String so a human can read it, but where people run into trouble is when they start thinking of a date in terms of format. Format is for readability, not for calculations. java.util.Date and java.util.Calendar are fraught with issues (Effective Java, Bloch, et. al. has plenty to say about it) but are still the norm if you need handy date operations.

How to properly store end date in database

Application: Java + ExtJS
There are a lot of different entity with properties of java.util.Date type: startDate and iesendDate (endDate could be NULL). Both dates could be selected with or without time part (e.g. time part is always persisted, event if it is not selected). For example, like this:
2010-07-01 00:00:00
Possible problems start when user selects endDate without time. For example, period starts on 2010-07-01 and ends on 1010-07-04. Right now in database it is stored like:
startDate="2010-07-01 00:00:00"
endDate="2010-07-04 00:00:00".
So it seems that period ends on the FIRST second of 2010-07-04. But as user assume, that endDate is implicitly included, e.g. period ends on LAST second of 2010-07-04. There are a lot of date comparisons for different periods in the system.
How in this case to store end date properly?
I thought about possible solutions, but all of them seems a bit wrong:
To store time part for end date like this: "2010-07-04 23:59:99". But then seems that end date day is not 24h - but (24h - 0.(9) millisecond), that could be potential problem. Also time part looks quite ugly.
To modify ExtJs component that it will add 1 day to date selected by user on persistance stage and substract 1 day again when this date will be shown to user (except cases when the user explicitly set time part). I don't like here that dates with time part and without it are treated differently.
To save only start date as Date object, and then save length of period in seconds, for example. This approach seems quite good - but a have to rework the whole application and possible it will be no very easy to use different comparisons on end dates.
Just use current one - save non-enclusive end date without time and be very careful during dates comparisons
Could someone explain the most widely used practices to solve such problem?
I've recently changed from your first approach to your second approach.
Approach 1: "2010-07-04 23:59:99" should be "2010-07-04 23:59:59" but anyway it is indeed ugly and technically there is a lost second. Another issue I did have is that I wanted to start one record with the same data/time as another record was stopped. So it was possible to find the successor of a record. And with approach 1 this cannot be done as the time will differentiate 1 second.
Approach 2: The end date will be "2010-07-05" and the query condition will be < endDate instead of <= endDate for approach 1. Here the end date is meaning 'till' or 'until' or 'up to' and not like in approach 1 'up to and including'. For this reason in new projects I do use tillDate or actually I use something like serviceStart / serviceTill.
The disadvantage is indeed to format it -1 day when showing to the user. But for me this makes sense.
Add end date as +1 day of user selected value.
Separate model and presentation
Do separate the stored end time in your database completely from the presentation of the end time to the user.
Store end date and time in database: Since you always store both date and time, you should clearly store the true date and time. If the period end at midnight between July 4 and 5, store this time, so 2010-07-05 00:00:00.
Present to the user: How your user would like to see that end time, I cannot say, and you should ask the users themselves. Maybe they will tell you:
As it is. 2010-07-05 00:00:00.
As 24 hours on the last day of the period, 2010-07-04 24:00:00.
As the last day as date only 2010-07-04 (I consider this unlikely, especially of the start time is not at midnight).
Or something else.
So yes, it’s very likely that you will have to treat end at midnight specially for presentation. It is not nearly as bad as if you had needed to treat it specially in your business logic.

Scala/java sanitize day of month above 31 or below 1?

Using JodaTime library (although I am a bit flexible). I realized some of the inputs coming in are breaking Joda time because the days of the month are above 31 or below 1 (because of client-side code).
I am using the LocalDate object for calendar manipulation. Is there a library or method to easily sanitize the dates so the input doesn't start throwing exceptions?
Some Scala code I am using now: EDIT: Fixed code
val now = new LocalDate();
val workingDate = now.withYear(y).withMonthOfYear(m).withDayOfMonth(d).withDayOfWeek(DateTimeConstants.SUNDAY)
ymdStart = toTimestampAtStart( workingDate )
For clarification, the goal here is to convert the date to a proper date, so if a user submitted July 38, it would convert to August 7. There's an incoming URL structure causing a lot of this and it looks like /timeline/2012/07/30.
For reasons of pure exercise (I agree normalization seems to be bad practice) I'm now just purely curious if there are libraries that deal with such a problem.
Thanks!
Final Update:
Like the answer points out, normalization was a poor idea. I did a lot of re-factoring on the client side to fix the incoming variables. This is the code I ended up using:
ymdStart = new Timestamp( toTimestampAtStart( new LocalDate(y,m,d).withDayOfWeek(1) ).getTime - 86400000 )
ymdEnd = new Timestamp( ymdStart.getTime + 691200000 )
First of all, a LocalDate is immutable, so each chained with...() is creating a new date.
Second, it is a well-known antipattern to update pieces of a date one at a time. The end result will depend on the current value of the date, the order in which you update the pieces, and whether or not the implementation "normalizes" dates.
In other words NEVER update a date/time piecemeal.
Assume for a minute that the implementation "normalizes" (i.e. corrects for overflow) invalid dates. Given your code, if today's date was 31-Jan-2011 and you did
now.setMonth(FEBRUARY);
now.setDayOfMonth(12);
the result will be 12-March-2011. The first statement sets the date to 31-February, which gets normalized to 03-March, then the day gets set to 12. Ah, you say, you can just set the day-of-month first. But that doesn't work for different starting points (construction of which is left as an exercise).
And from your question I surmise that JodaTime throws exceptions rather than normalize, which is anothe reason for not doing it this way.

Why was Date.getTimezoneOffset deprecated?

The documentation for Date.getTimezoneOffset says:
Deprecated. As of JDK version 1.1, replaced by
-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000).
Why was it deprecated? Is there a shorter way (Apache Commons?) to get the offset from UTC in hours/minutes? I have a Date object ... should I convert it to JodaDate for this?
And before you ask why I want the UTC offset - it's just to log it, nothing more.
There are 2 questions here.
Why was Date.getTimezoneOffset deprecated?
I think it is because they actually deprecated nearly all methods of Date and moved their logic to calendar. We are expected to use generic set and get with the parameter that says which specific field we need. This approach has some advantages: less number of methods and the ability to run setters in a loop passing a different field each time. I personally used this technique a lot: it makes code shorter and easier to maintain.
Shortcut? But what's wrong with call
Calendar.get(Calendar.DST_OFFSET) comparing to
Calendar.getTimeZoneOffset()
As far as I can see the difference is 6 characters.
Joda is a very strong library and if you really have to write a lot of sophisticated date manipulation code switch to it. I personally use the standard java.util.Calendar and don't see any reason to use external libraries: good old calendar is good enough for me.
All of the date manipulation logic was moved out of Date once the Java implementers realized that it might need to be implemented differently for different types of calendars (hence the need to use a GregorianCalendar to retrieve this info now). A Date is now just a wrapper around a UTC time value.
Take care before you paste code from this page.
Perhaps just me but I believe that in order to get the tz offset in minutes you need to do
int tzOffsetMin = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
rather than what the Javadoc says, which is:
int tzOffsetMin = -(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
Calendar.ZONE_OFFSET gives you the standard offset (in msecs) from UTC. This doesn't change with DST. For example for US East Coast timezone this field will always be -6 hours regardless of DST.
Calendar.DST_OFFSET gives you the current DST offset (in msecs) - if any. For example during summer in a country that uses DST this field is likely to have the value +1 hour (1000*60*60 msecs).

Using GregorianCalendar.setGregorianChange for calculating time difference

I'm reading Uncle Bob's "The Craftsman" series, and have gotten to #29 (PDF). In it, there's this snippet in test code, for asserting dates are close enough:
private boolean DatesAreVeryClose(Date date1, Date date2) {
GregorianCalendar c1 = new GregorianCalendar();
GregorianCalendar c2 = new GregorianCalendar();
c1.setGregorianChange(date1);
c2.setGregorianChange(date2);
long differenceInMS = c1.getTimeInMillis() - c2.getTimeInMillis();
return Math.abs(differenceInMS) <= 1;
}
I read the docs, and yet couldn't figure why simply using Date.getTime() isn't good enough instead of introducing the calendar etc. Am I missing some corner cases?
Time on the spaceship is different from time in our world. Also, the java API on the spaceship is slightly different from the API in our world. The method setGrogorianChange has nothing to do with julian dates in the spaceship world. Rather it is a way to set the time of the GregorianCalendar instance. And in the spaceship world, Date.getTime() does not return milliseconds. It returns a hashed value that somehow represents the time, but cannot be subtracted or added.
So there.
I'm going to bite: that code is utter rubbish. If the use of setGregorianChange() has any purpose at all (which I doubt), it is the kind of clever hack that has no business anywhere near real world code. But I strongly suspect that whoever wrote that cutesy story just didn't know the Date/Calendar API very well and really meant to use Calendar.setTime().
The case against directly comparing Date instances in assertEquals() seems to be that the instances' internal timestamps may differ by milliseconds, even if created right after on another - thus the introduction of a "fuzzy compare" in the form of Math.abs(differenceInMS) <= 1. But neither does that require the detour via GregorianCalendar, nor is it enough fuzz - a full GC or even just the clock granularity could easily lead to two dates created right after another being 10 or more ms apart.
The real problem is the lack of a "calendar date" datatype in Java - making comparisons with day granularity pretty verbose (you have to use a Calendar to set all time fields to 0). Joda Time's DateMidnight class is what is really needed here.
There is no good reason not to use Date.getTime(). Most likely, the author was falling back on his familiar use of the GregorianCalendar object for doing date/time manipulation.
On a side note, use of setGregorianChange to get this information seems... abusive of the API. The method is used to set "the point when the switch from Julian dates to Gregorian dates occurred. Default is October 15, 1582 (Gregorian). " (javadoc) It may work to make the given calculation, but it makes things pretty hard to understand from a code maintenance point of view.

Categories

Resources