I insert some data into Sqlite database and check before insert if record for this day allready exists. To check this I have to see if number of days are >0. For example difference (in days) between 2011-8-6 and 2011-8-5 is 1. How to do this in Java?
EDIT:
As #RayToal mentioned this could be done in database, so I did on that way:
SELECT julianday('now') - julianday(Date(Date)) from VIDEO_HISTORY;
Only problem with this is that it gives me decimal number. For example: 3.3442346529103816
Now I have to decide inside Java if given number is 3 of 4 days.
It code is for app that searches youtube for some term and writes statistical data about daily views into database. User is able to schedule job for example every day in 20:00 o'clock. But then he could decide to reschedule this job in 10:00 o'clock, so program has to understood this like difference is one day. So it's obvious that I have to round to first bigger number. Is there some method for this or I have to write myself?
EDIT2: According to links provided by #Michael-O this is best solution (using JodaTime):
DateTime start = new DateTime(new GregorianCalendar(2011, 8, 4).getTime());
DateTime end = new DateTime(new GregorianCalendar(2011, 8, 8).getTime());
int numberOfDays = Days.daysBetween(start.toDateMidnight(), end.toDateMidnight()).getDays();
System.out.println(numberOfDays);
You may want to consult this tutorial. Moreover you should consider using Joda Time's Period and consult this answer on stackoverflow.
If you want the number of calendar days (a Period in java.time parlance), then use (in Java 8):
import java.time.temporal.ChronoUnit;
import java.time.LocalDate;
ChronoUnit.DAYS.between(LocalDate.parse(from.toString()),LocalDate.parse(to.toString())
(This avoids a subtle bug in Java 8's java.sql.Date API)
If you want a Duration in days (physically elapsed time in 24-hour units), then use Marcelo's approach.
Related
I have a question. I've never did that before. So how I can to convert time in format, what Google Places Api is giving me, and to get hour of day from that?
From the Google Places API documentation:
periods[] is an array of opening periods covering seven days, starting from Sunday, in chronological order.
Each period contains:
open contains a pair of day and time objects describing when the place opens:
day a number from 0–6, corresponding to the days of the week, starting on Sunday. For example, 2 means Tuesday.
time may contain a time of day in 24-hour hhmm format (values are in the range 0000–2359). The time will be reported in the place’s timezone.
close may contain a pair of day and time objects describing when the place closes. Note: If a place is always open, the close section will be missing from the response. Applications can rely on always-open being represented as an open period containing day with value 0 and time with value 0000, and no close.
Based on this, it's up to you to parse the information and format it appropriately.
Why are you trying to parse out JSON? If you're using Java, stick to Java. You have access to the actual objects. What's the point in using the client services API?
PlaceDetails place = PlacesApi.placeDetails(new GeoApiContext.Builder().apiKey(API_KEY).build(), "insert place id");
for (Period period : place.openingHours.periods)
{
LocalTime time = period.open.time;
}
I have a date in the far past.
I found out what the duration is between this date and now.
Now I would like to know - how much is this in years?
I came up withthis solution using Java8 API.
This is a monstrous solution, since I have to convert the duration to Days manually first, because there will be an UnsupportedTemporalTypeException otherwise - LocalDate.plus(SECONDS) is not supported for whatever reason.
Even if the compiler allows this call.
Is there a less verbous possibility to convert Duration to years?
LocalDate dateOne = LocalDate.of(1415, Month.JULY, 6);
Duration durationSinceGuss1 = Duration.between(LocalDateTime.of(dateOne, LocalTime.MIDNIGHT),LocalDateTime.now());
long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDate.now(),
LocalDate.now().plus(
TimeUnit.SECONDS.toDays(
durationSinceGuss1.getSeconds()),
ChronoUnit.DAYS) );
/*
* ERROR -
* LocalDate.now().plus(durationSinceGuss1) causes an Exception.
* Seconds are not Supported for LocalDate.plus()!!!
* WHY OR WHY CAN'T JAVA DO WHAT COMPILER ALLOWS ME TO DO?
*/
//long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDate.now(), LocalDate.now().plus(durationSinceGuss) );
/*
* ERROR -
* Still an exception!
* Even on explicitly converting duration to seconds.
* Everything like above. Seconds are just not allowed. Have to convert them manually first e.g. to Days?!
* WHY OR WHY CAN'T YOU CONVERT SECONDS TO DAYS OR SOMETHING AUTOMATICALLY, JAVA?
*/
//long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDate.now(), LocalDate.now().plus(durationSinceGuss.getSeconds(), ChronoUnit.SECONDS) );
Have you tried using LocalDateTime or DateTime instead of LocalDate? By design, the latter does not support hours/minutes/seconds/etc, hence the UnsupportedTemporalTypeException when you try to add seconds to it.
For example, this works:
LocalDateTime dateOne = LocalDateTime.of(1415, Month.JULY, 6, 0, 0);
Duration durationSinceGuss1 = Duration.between(dateOne, LocalDateTime.now());
long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDateTime.now(), LocalDateTime.now().plus(durationSinceGuss1) );
System.out.println(yearsSinceGuss); // prints 600
Although the accepted answer of #Matt Ball tries to be clever in usage of the Java-8-API, I would throw in following objection:
Your requirement is not exact because there is no way to exactly convert seconds to years.
Reasons are:
Most important: Months have different lengths in days (from 28 to 31).
Years have sometimes leap days (29th of February) which have impact on calculating year deltas, too.
Gregorian cut-over: You start with a year in 1415 which is far before first gregorian calendar reform which cancelled full ten days, in England even 11 days and in Russia more. And years in old Julian calendar have different leap year rules.
Historic dates are not defined down to second precision. Can you for example describe the instant/moment of the battle of Hastings? We don't even know the exact hour, just the day. Assuming midnight at start of day is already a rough and probably wrong assumption.
Timezone effects which have impact on the length of day (23h, 24h, 25h or even different other lengths).
Leap seconds (exotic)
And maybe the most important objection to your code:
I cannot imagine that the supplier of the date with year 1415 has got the intention to interprete such a date as gregorian date.
I understand the wish for conversion from seconds to years but it can only be an approximation whatever you choose as solution. So if you have years like 1415 I would just suggest following very simple approximation:
Duration d = ...;
int approximateYears = (int) (d.toDays() / 365.2425);
For me, it is sufficient in historic context as long as we really want to use a second-based duration for such an use-case. It seems you cannot change the input you get from external sources (otherwise it would be a good idea to contact the duration supplier and ask if the count of days can be supplied instead). Anyway, you have to ask yourself what kind of year definition you want to apply.
Side notes:
Your complaint "WHY OR WHY CAN'T JAVA DO WHAT COMPILER ALLOWS ME TO DO?" does not match the character of new java.time-API.
You expect the API to be type-safe, but java.time (JSR-310) is not designed as type-safe and heavily relies on runtime-exceptions. The compiler will not help you with this API. Instead you have to consult the documentation in case of doubt if any given time unit is applicable on any given temporal type. You can find such an answer in the documentation of any concrete implementation of Temporal.isSupported(TemporalUnit). Anyway, the wish for compile-safety is understandable (and I have myself done my best to implement my own time library Time4J as type-safe) but the design of JSR-310 is already set in stone.
There is also a subtile pitfall if you apply a java.time.Duration on either LocalDateTime or Instant because the results are not exactly comparable (seconds of first type are defined on local timeline while seconds of Instant are defined on global timeline). So even if there is no runtime exception like in the accepted answer of #Matt Ball, we have to carefully consider if the result of such a calculation is reasonable and trustworthy.
Use Period to get the number of years between two LocalDate objects:
LocalDate before = LocalDate.of(1415, Month.JULY, 6);
LocalDate now = LocalDate.now();
Period period = Period.between(before, now);
int yearsPassed = period.getYears();
System.out.println(yearsPassed);
I have a datepicker where the user selects a date and then a checkbox on what type of period he wants to get the date from. For example:
User selects the 1. of November and selects the checkbox "Month" in this case the end date will be increased by 1 and even if this sound simple enough its slowly starting to annoy me alot!
The problem is that Java doesnt have a great date object that works for this kind of thing so i thought that i would use Calendar but it isnt easy to increment a calendar date take for instance the following example:
endDate.set(startDate.YEAR, startDate.MONTH+1, startDate.DATE);
in theory this would increment the month by one being one larger than the start date. This works in about 90 % of the months EXECPT from December if you increase the month by 1 in December then the integer month return 13 same thing happens for startDate.DATE; and startDate.Year;
My question is isnt there an easier way to do this? i could make a ton of If sentences but i really think that it is kinda redundant.
Use add method of java.util.Calendar.
endDate.set(startDate.YEAR, startDate.MONTH, startDate.DATE);
if(some_condition) {
endDate.add(Calendar.MONTH, 1);
}
You can use Calendar.add() to add values to the calendar value, e.g. Calendar.add(Calendar.MONTH, 1) this adds one month and takes into account that January is after December.
The standard recomendation here is to look at Joda-Time (see here for more info). It's a much more consistent/capable API with none of the threading issues that plague the standard Java date/formatting APIs and as such is widely used and accepted.
In terms of what you want above, I would suggest something like:
LocalDate d = ...
LocalDate nd = d.plusMonths(1);
The above will correctly handle month/year rollovers.
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.
So me and my partner have been working on this project for a while now. We work with dates A LOT in this project, and we recently noticed an issue, and we are rather deep in at this point.
We store our times in SQLlite (Android project) as a formatted string, since a lot of the time they are directly bound to listviews and such.
The problem we noticed, which i found kind of odd, is that that SimpleDateTimeFormat object, when used to format to 24h time (its a medical based project, so 24h time is the convention here) 12:00am-12:59am are formatted to 24:00-24:59, instead of 00:00-00:59...
This isn't too much of an issue until we query the database and order the results by the dates, any data that is between 12:00am and 12:59am will show up at the end of the list, but it should show up at the beginning...
Anyone else encountered this problem? or know a way around it? The best thing possible would be a way to store the data as 00:00 not 24:00.
Cheers
I strongly suspect you're using the wrong pattern. We've got to guess as you haven't posted any code (hint, hint), but I suspect you're using a pattern such as
kk:mm:ss
instead of
HH:mm:ss
Sample code:
import java.util.*;
import java.text.*;
public class Test {
public static void main(String[] args) throws Exception {
SimpleDateFormat broken = new SimpleDateFormat("kk:mm:ss");
broken.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
SimpleDateFormat working = new SimpleDateFormat("HH:mm:ss");
working.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
Date epoch = new Date(0);
System.out.println(broken.format(epoch));
System.out.println(working.format(epoch));
}
}
Additionally, as others have pointed out, you shouldn't be storing your values in string format to start with... avoid string conversions wherever you can, as each conversion is a potential pain point.
Please read this and this about how SQLite stores dates (or doesn't store dates). SQLite doesn't have a "Date" type, so it is stored as a string. You should store your date as an integer (milliseconds), and then you can use date and time functions to pull them out (from the first link).
From the documentation
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS"). REAL as Julian
day numbers, the number of days since noon in Greenwich on November
24, 4714 B.C. according to the proleptic Gregorian calendar. INTEGER
as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these
formats and freely convert between formats using the built-in date and
time functions.
I prefer INTEGER / Unix time storage, then use the built in date and time functions to format when pulling from DB.
EDIT: Also, this will take care of sorting. I'm guessing your current "sorting" of the dates in SQLite is string based, which is bad mmmmkay.
What is the format string you are passing to your SimpleDateFormat? According to the docs, using 'H' for the hours should get you 0-23, using 'k' should get you 1-24.