number of periods (custom) between two dates - java

I want to find out how many periods (custom) are there between two dates. Like how many weeks are between 1 july to 2nd Aug or how many half months are there between 2 nd Juy and 14 Dec, where in half month would be customizable whether it ends on 15th or 16th.
IS there any library where this or something similar has been done? Not that its tricky but just want to know if such things exists.

Joda Time is great but it doesn't have direct support for your needs, although it represents the concepts you want to handle
http://joda-time.sourceforge.net/quickstart.html
In particular, see http://joda-time.sourceforge.net/key_period.html
and the methods .dividedBy(int) and .multipliedBy(int)

Related

Bug or Feature? Java 16 DateTimeFormatter issue with parsing localized month name

I'm using the en_GB locale, but a similar issue may also affect other en_XX locales.
Under Java 15 the following code works:
LocalDate.parse("10-Sep-17", DateTimeFormatter.ofPattern("dd-MMM-yy", Locale.UK));
Under Java 16 it gives: DateTimeParseException: Text '10-Sep-17' could not be parsed at index 3
After spending a long time in the debugger I have traced this to this commit: 8251317: Support for CLDR version 38
This commit changes the abbreviated form of September in make/data/cldr/common/main/en_GB.xml from Sep to Sept for both the context-sensitive and standalone forms. None of the other months are touched, remaining as 3 characters.
I have verified that this is indeed a genuine change between CLDR versions 37 and 38, although I'm not sure when we Brits switched to using 4 letters for our 3-letter abbreviation for September...
Now this is annoying, as it has broken my datafile processing (although I suspect I can fix it by specifying Locale.ENGLISH rather than using the default locale in my code), but I can't decide if it counts as a bug that has been introduced that breaks my reliable 3-character-month match pattern, or whether this is actually meant to be a feature.
The JavaDoc says:
Text: The text style is determined based on the number of pattern letters used. Less than 4 pattern letters will use the short form. ...
and later:
Number/Text: If the count of pattern letters is 3 or greater, use the Text rules above. Otherwise use the Number rules above.
My bad for never having read this carefully enough to spot that textual values are handled differently to numbers, where the number of letters in your pattern sets the width. But this leaves me wondering how you are supposed to specify a fixed number of characters when you output a month, and equally why it can't be permissive and accept the three-character form when parsing rather than throw an exception?
At the end of the day this still feels like a regression to me. My code that has worked reliably for years parsing dates with 3-character months in now, with no warning, fails on all dates in September. Am I wrong to think this feels incorrect?

How many days from now is the Duration?

I have a Duration, like P3M (3 months). How can I get number of days it is from now?
All I have now is this:
Duration.parseWeekBasedPeriod("P3M")
I know the period parameter will never be shorter than 1 week, so parseWeekBasedPeriod() should be ok. But I'm reading JavaDoc, and I can't figure out how to get those days.
I understand, the problem is that months can has 31, 30, 29 and 28 days.
Using parseWeekBasedPeriod(...) is certainly wrong if you want to apply durations measured in months. This very special method handles week based years which can last either 364 or 371 days (52 or 53 weeks). So I suggest just to use the standard parsing method for calendar-based durations. The following code also strongly simplifies the evaluation of days between two dates (see last line).
Duration<CalendarUnit> duration = Duration.parseCalendarPeriod("P3M");
PlainDate today = PlainDate.nowInSystemTime();
PlainDate later = today.plus(duration);
long days = CalendarUnit.DAYS.between(today, later);
By the way, I have tested the method for weekbased durations once again. It will usually throw an exception if it tries to parse months. You didn't seem to have seen any exception so I assume that the fact that you use untyped constructs like "val" has shadowed the necessary type information in processing the duration string (and Time4J is a strongly typed library). Hence - if technically possible for you -, I strongly recommend to use type-safe code as shown in my solution.
Finaly figured it out:
val period = Duration.parseWeekBasedPeriod("P3M")
val start = PlainDate.nowInSystemTime()
val end = start.plus(period)
val days: Long = Duration.`in`(CalendarUnit.DAYS).between(start, end).getPartialAmount(CalendarUnit.DAYS)

What's the best way to get the number of days in a month using the java.time API?

I need to determine the number of days in the month represented by the month portion of a java.time.ZonedDateTime. I've come up with three ways that appear to work. Given:
ZonedDateTime date = _some date_;
Option 1:
int daysInMonth = date.getMonth().length(date.getChronology().isLeapYear(date.getYear()));
Option 2:
int daysInMonth = date.getMonth().length(date.toLocalDate().isLeapYear());
Option 3:
int daysInMonth = YearMonth.from(date).lengthOfMonth();
I discovered option 3 while checking this question for duplicates (Number of days in particular month of particular year?). Am I missing any other options? Is one of these options superior to another? Under what circumstances will that superiority manifest?
If I'm reading things correctly, the first one appears to be the only one capable of supporting chronologies other than IsoChronology. That's not important for the use case at hand, but I do like to write flexible, reusable code, and I'd like for this to not fall down in other situations. I'm not an expert on those alternative chronologies, and I don't know if they have leap years or anything else that might cause the length of a month to vary. Heck, I don't even know if they have months.
EDIT: Option 4, per #Ole V.V.'s answer, below:
int daysInMonth = date.toLocalDate().lengthOfMonth();
int daysInMonth = date.toLocalDate().lengthOfMonth();
I understand your confusion. There are several ways to do this, and the above is not the only good way. In particular I’m pretty fond of your option 3 too. The options explicitly involving isLeapYear() are not to my taste, I find them too low-level, too manual.
Under what circumstances will that superiority manifest?
Readability and absence of surprises are the kings. From there your judgement is at least as good as mine. Chances are that you know the people who are going to maintain your code better than I do.
You may also take a step back and ask yourself what you need the number of days in a month for. I am mentioning this because one typical use would be for calculations that java.time can itself do better than you can, like adding 24 days to a date, finding the count of days between two dates in different months or finding out which day of the year a certain date is. java.time has got methods for all of these and many more.

How to identify date from a string in Java

Recently I am being challenged by quite an "easy" problem. Suppose that there is sentences (saved in a String), and I need to find out if there is any date in this String. The challenges is that the date can be in a lot of different formats. Some examples are shown in the list:
June 12, 1956
London, 21st October 2014
13 October 1999
01/11/2003
Worth mentioning that these are contained in one string. So as an example it can be like:
String s = "This event took place on 13 October 1999.";
My question in this case would be how can I detect that there is a date in this string. My first approach was to search for the word "event", and then try to localize the date. But with more and more possible formats of the date this solution is not very beautiful. The second solution that I tried is to create a list for months and search. This had good results but still misses the cases when the date is expressed all in digits.
One solution which I have not tried till now is to design regular expressions and try to find a match in the string. Not sure how much this solution might decrease the performance.
What could be a good solution that I should probably consider? Did anybody face a similar problem before and what solutions did you find?
One thing is for sure that there are no time, so the only interesting part is the date.
Using the natty.joestelmach.com library
Natty is a natural language date parser written in Java. Given a date expression, natty will apply standard language recognition and translation techniques to produce a list of corresponding dates with optional parse and syntax information.
import com.joestelmach.natty.*;
List<Date> dates =new Parser().parse("Start date 11/30/2013 , end date Friday, Sept. 7, 2013").get(0).getDates();
System.out.println(dates.get(0));
System.out.println(dates.get(1));
//output:
//Sat Nov 30 11:14:30 BDT 2013
//Sat Sep 07 11:14:30 BDT 2013
You are after Named Entity Recognition. I'd start with Stanford NLP. The 7 class model includes date, but the online demo struggles and misses the "13". :(
Natty mentioned above gives a better answer.
If it's only one String you could use the Regular Expression as you mentioned. Having to find the different date format expressions. Here are some examples:
Regular Expressions - dates
In case it's a document or a big text, you will need a parser. You could use a Lexical analysis approach.
Depending on the project using an external library as mentioned in some answers might be a good idea. Sometimes it's not an option.
I've done this before with good precision and recall. You'll need GATE and its ANNIE plugin.
Use GATE UI tool to create a .GAPP file that will contain your
processing resources.
Use the .GAPP file to use the extracted Date
annotation set.
Step 2 can be done as follows:
Corpus corpus = Factory.newCorpus("Gate Corpus");
Document gateDoc = Factory.newDocument("This event took place on 13 October 1999.");
corpus.add(gateDoc);
File pluginsHome = Gate.getPluginsHome();
File ANNIEPlugin = new File(pluginsHome, "ANNIE");
File AnnieGapp = new File(ANNIEPlugin, "Test.gapp");
AnnieController =(CorpusController) PersistenceManager.loadObjectFromFile(AnnieGapp);
AnnieController.setCorpus(corpus);
AnnieController.execute();
Later you can see the extracted annotations like this:
AnnotationSetImpl ann = (AnnotationSetImpl) gateDoc.getAnnotations();
System.out.println("Found annotations of the following types: "+ gateDoc.getAnnotations().getAllTypes());
I'm sure you can do it easily with the inbuilt annotation set Date. It is also very enhancable.
To enhance the annotation set Date create a lenient annotation rule in JAPE say 'DateEnhanced' from inbuilt ANNIE annotation Date to include certain kinds of dates like "9/11" and use a Chaining of Java regex on R.H.S. of the 'DateEnhanced' annotations JAPE RULE, to filter some unwanted outputs (if any).

Finding Timestamp pattern from a String

I want to convert a String into Timestamp, the pattern for which is unknown. Is there any API given by java which allows us to feed in the string and returns the possible patterns that could work with it? I understand that one could have some pre-defined patterns against which the String can be parsed and checked. But, since this is a timestamp, the number combinations of different dates and times will be quite a lot. So, was looking for an efficient way of figuring out the pattern of the String-Timestamp.
Never heard about ready-to-use library for something like this, as #Eugene noted, possible combinations for all the patterns is huge so there is probably no such a library.
I would recommend rethinking your architecture.
If you just want to play with something like this you can create your own implementation.
Lets say that you parse the input and then you figure out the array of integers
(09, 21, 12, 0, 44, 33)
, you can assume that the array contains year, day, month, minute, hour and seconds (not sure if you can assume that - its just an example)
Once you have that array you can create all possible permutations of this array - example here
Then you can create a Date object for each combination:
DateTime dt = new DateTime(09, 12, 21, 0, 44, 33, 0);
(above example is for JodaTime)
If you know for example that the year value will always be sent with 4 characters then possible number of combinations will decrease of course, further you can assume that '26' will not be the value for the month etc.. you probably get the idea.
In this case , first I would switch to Joda Time : http://joda-time.sourceforge.net/
Then I would generate some (try to decrease the possibilities as much as you can, as there are way too many) the Patterns and try the date over them. If it does not throw an error (aka it fits, put it in an array), then return the array. This is probably a very non-optimized solution, but this is where I would start.
I really do not think that there are libraries for that. Also, you might want to explain why you want to do that. may be the solution is a bit simpler.
Cheers,
Eugene.

Categories