If I calculate the difference between 2 LocalDate's in java.time using:
Period p = Period.between(testDate, today);
Then I get an output with the number of years, months, days like:
Days = 9
Months = 6
Years = 18
Does anyone know a clean way to represent that as a decimal type value (ie, above would be something around 18.5...)?
You mentioned in one of your comments that you need quarter year precision if you need the current quarter you can use IsoFields.QUARTER_YEARS:
double yearAndQuarter = testDate.until(today, IsoFields.QUARTER_YEARS) / 4.0;
This way you will actually use the time api, always get the correct result and #Mike won't have to loathe anything.
Please do not do this.
Representing the difference between two dates as a 'number of years' multiplier is problematic because the average length of a year between two dates is dependent on which dates you are comparing. It's easy to get this wrong, and it's much harder to come up with all the test cases necessary to prove you got it right.
Most programmers should never perform date/time calculations manually. You are virtually guaranteed to get it wrong. Seriously, there are so many ways things can go horribly wrong. Only a handful of programmers on the planet fully understand the many subtleties involved. The fact that you are asking this question proves that you are not one of them, and that's okay--neither am I. You, along with the vast majority of us, should rely on a solid Date/Time API like java.util.time.
If you really need a single numeric value, then the safest option I can think of is to use the number of days, because the LocalDate API can calculate that number for you:
long differenceInDays = testDate.until(today, ChronoUnit.DAYS)
Note that this difference is only valid for the two dates used to produce it. The round-trip conversion is straightforward:
LocalDate today = testDate.plus(differenceInDays, ChronoUnit.DAYS)
Do not attempt to manually convert a Period with year, month, and day components into a whole number of days. The correct answer depends on the dates involved, which is why we want to let the LocalDate API calculate it for us.
When precision isn't important
Based on your comments, precision isn't an issue for you, because you only want to display someone's age to the nearest quarter-year or so. You aren't trying to represent an exact difference in time; only an approximate one, with a rather large margin for error. You also don't need to be able to perform any round-trip calculations. This changes things considerably.
An approximation like #VGR's should be more than adequate for these purposes: the 'number of years' should be accurate to within 3 days (< 0.01 years) unless people start living hundreds of thousands of years, in which case you can switch to double ;).
#Oleg's approach also works quite well, and will give you a date difference in whole quarters, which you can divide by 4 to convert to years. This is probably the easiest solution to get right, as you won't need to round or truncate the result. This is, I think, the closest you will get to a direct solution from java.util.time. The Java Time API (and date/time APIs in general) are designed for correctness: they'll give you whole units, but they usually avoid giving you fractional approximations due to the inherent error involved in floating-point types (there are exceptions, like .NET's System.TimeSpan).
However, if your goal is to present someone's age for human users, and you want greater precision than whole years, I think 18 years, 9 months (or an abbreviated form like 18 yr, 9 mo) is a better choice than 18.75 years.
I would avoid using Period, and instead just calculate the difference in days:
float years = testDate1.until(today, ChronoUnit.DAYS) / 365.2425f;
Related
Some years ago, I helped write an application that dealt with money and insurance. Initially, we represented money with floating point numbers (a big no-no, I know). Most of the application was just adding and subtracting values, so there weren't any issues. However, specific portions dealt with percentages of money values, hence multiplication and division.
We immediately began suffering from floating point errors and had to do a major refactor. We used an arbitrary precision library which solved that issue. However, it didn't change the fact that you can end up with fractions of a cent. How are you supposed to round that? The short answer is "it's complicated."
Now I'm getting ready to begin work on a similar application to supplant the old one. I've been mulling this over for years. I always thought it would be easiest to create a money datatype that wraps an integer (or BigInteger) to represent the number of pennies with a function to print it to a traditional, human-friendly $0.00 format.
However, researching this, I found JSR 354, the Java Money API that was recently implemented. I was surprised to discover that it backs its representation of money with BigDecimal. Because of that, it includes specific logic for rounding.
What's the advantage to carrying fractions of a cent around in your calculations? Why would I want to do that instead of saying one cent is the "atomic" form of money?
This is a broad question because its answer differs for its implementation.
If I were to purchase 1000 items in bulk for $5, then each item would individually cost $0.005, which is less than what you claim to be the "atomic form" of money, $0.01.
If we considered $0.01 to be the lowest possible amount, then we wouldn't be able to handle calculations in specific situations, like the one in my example.
For that reason, the JavaMoney API handles many fractional digits, ensuring that no precision is lost in cases like these.
I'm writing an application in Java, and trying to get the best performance out of it. Currently it can handle 250,000 of a specific operation every second.
However, I discovered a bug. Due to the way this application works I have to take a number that is from the user input, that can be up to x,xxx,xxx,xxx and then to this I also have to add a timestamp in milliseconds.
Of course, I forgot about this and soon discovered that all of my values were negative.
Now, initially my thought was to just use BigIntegers, but will this not destroy the performance?
What is the best way to handle large integers in low latency applications.
There's no reason for BigInteger. I can see just 10 digits there, which means that it nearly fits in an int. A long gives you 9 more digits.
Look at Long.MAX_VALUE and similar constants so you know what you're doing. A millisecond timestamp in long will overflow on Sun Aug 17 07:12:55 GMT 292278994. That's not a typo.
you can use long for 10 digits.
Or, you can try java.math.BigInteger or java.math.BigDecimal.
I'm writing a Java program that automatically generates a certain amount of "units" for the user to do (Actual purpose not important in this question).
I'm struggling to find a good way to determine how many of these "units" to give the user for the next week.
Intentions of the calculation :
Gives "units" of a specific week
Calculates units for the week based on the actual day of the week (Mon-Fri)
Accounts for all of the units that month (Ex. If it is the last week of the month, give all possible units that entire week)
If estimating, should over-estimate (Due to the program's nature, under-estimating would be far worse.)
Units cannot be decimals (Hence the cast to int)
Variables I have :
The amount of "units" to do that month
I have tried to do this in a few different ways, and so far, the best way I have is this :
public static int getRemainingUnitsThisWeek() {
return (int) Math.round(((double) getUnitsThisMonth() / (((30 - (double) DateTime.now().getDayOfMonth()+1) / 7) < 1 ? 1 :
((30 - (double) DateTime.now().getDayOfMonth()+1) / 7))) / (double)DateTime.now().getDayOfWeek());
}
The problem that I end up (specifically, I'm still not happy with how it does it) with is that in the "units" given on the last week of the month is still divided by the day of the week (Which in turn gives you a much lower number each day - even though the user needs to receive all the "units" by the end of the month).
Any questions you might have, just ask!
PS. The library I am using in the DateTime.now() function is joda-time.
Your description is confusing, so I'm not sure I can answer it directly. Instead, I will answer a different question, which may help:
I have a bunch of units to do, and the rest of the month to do them.
How many should I do today?
I don't know about Joda, but using the standard Date API, you can use this answer to get a Date representing the end of the month, a similar technique to get a Date representing the end of today, and new Date() to get the current time. Then subtract their getTime()s. You can then apportion your units now that you know how many milliseconds to the end of the day and the end of the month.
units_today = total_units_to_do * milliseconds_to_end_of_today /
milliseconds_to_end_of_month;
I don't know java, so I won't attempt to write code, but I suggest you start by calculating daysLeftInMonth and daysLeftInWeek. Once you get those working perfectly, you have two simple cases: either the month will end before the week does, or else it won't.
In the first case the rest of the algorithm is trivial. In the second, calculate how many units there should be per day (rounding up), then multiply by the days left in the week.
I read that for handling date range query NumericRangeQuery is better than TermRangeQuery in "Lucene in action", But i couldnot find the reason. i want to know the reason behind it.
I used TermRangeQuery and NumericRangequery both for handling date range query and i found that searching is fast via NumericRangeQuery.
My second point is to query using NumericRangeQuery i have to create indexes using NumericField by which i can create indexes upto milisecond but what if i want to reduce my resolution upto hour or day.
Why is numeric so much faster than term?
As you have noted, there is a "precision step". This means that numbers are only stored to a certain precision, which means that there is a (very) limited number of terms. According to the documentation, it is rare to have more than 300 terms in an index. Check out the wikipedia article on Tries if you are interested in the theory.
How can you reduce precision?
The NumericField class has a "precision" parameter in the constructor. Note that the range query also has a precision parameter, and they must be the same. That JavaDoc page has a link to a paper written about the implementation explaining more of what precision means.
Explanation by #Xodarap about Numeric field is correct. Essentially, the precision is dropped for the numbers to reduce the actual term space. Also, I suppose, TermRangeQuery uses String comparison whereas NumericRange query is working with integers. That should squeeze some more performance.
You can index at any desirable resolution - millisecond to day. Date.getTime() gives you milliseconds since epoch. You can divide this number by 1000 to get time with resolution at second. Or you can divide by 60,000 to get resolution at minute. And so on.
Just a day before I participated in the qualification round of Google Code Jam. This is my first experience of such an online coding contest. It was really fun.
There were three problems given of which i was able to solve two. But on one of the problems I was asked to work with values that are really huge. I am a Java guy and I thought I would go for double variable. Unfortunately, the precision of double also was not enough. Moreover, I attended this during the closing stage, I was not having the time to dig much into it (plus solving 1 is enough to qualify to the next stage).
My question is this, How to have a precision mechanism that is greater than double. My coding experience is in Java, so it would be great if you could please answer in that lines.
Thanks
Java has BigDecimall for arbitrary-precision arithmetic - but it's much, much slower than using double.
It's also possible that the problem in question was supposed to be soved by using algebraic transformations and e.g. work with logarithms.
If the problem requires integers you can use BigInteger.
Also, long is slightly better than double for integers, with 63 bits compared to 53 bits of precision (assuming positive numbers).
You can use arbitrary precision numbers, such as BigDecimal - it's slower but as precise as you specify.