date - How to calculate monthly occurrence in java -
i need able manage dates in flexible way calculating monthly events.
if use
simpledateformat sdf = new simpledateformat("dd-m-yyyy hh:mm:ss"); calendar calendar = calendar.getinstance(); calendar.set(2017, calendar.august, 31, 9, 30, 15); calendar next = calendar; (int = 1; i++<10;) { next = (calendar) calendar.clone(); next.add(calendar.month, i); system.out.println(sdf.format(next.gettime())); }
in result can see
31-10-2017 09:30:15
30-11-2017 09:30:15
31-12-2017 09:30:15
31-1-2018 09:30:15
28-2-2018 09:30:15
31-3-2018 09:30:15
30-4-2018 09:30:15
31-5-2018 09:30:15
30-6-2018 09:30:15
it seems following month semantic if add 1 moth date should next month (it's correct), following occurrence semantic has issue, because of acceptance same date day in next month (as can see not same sometimes. there 31
, 30
, 28
). if there no same date, should null
example.
does java provides ability calculate months following occurrence semantic strategy handle issue?
more explanation examples.
i not need last month day need occurrences first explanation 31th month day. simplified question possible.
i can workarounds calendar
expected more elegant solution.
if use ical4j calculate occurrences, you'll result. , occurrences calculation should fixed (it's bug because of rfc5545).
import net.fortuna.ical4j.model.* import net.fortuna.ical4j.model.component.vevent void testcalculaterecurrenceseton31th() { vevent event = new contentbuilder().vevent { dtstart('20100831t061500z', parameters: parameters() { value('datetime')}) dtend('20100831t064500z', parameters: parameters() { value('datetime')}) rrule('freq=monthly;until=20110101') } def dates = event.calculaterecurrenceset(new period('20100831t000000/20110131t000000')) def expected = new periodlist(true) expected.add new period('20100831t061500z/pt30m') expected.add new period('20101031t061500z/pt30m') expected.add new period('20101231t061500z/pt30m') println dates assert dates == expected /* assertion failed: assert dates == expected | | | | | [20100831t061500z/pt30m, 20101031t061500z/pt30m, 20101231t061500z/pt30m] | false [20100831t061500z/pt30m, 20100930t061500z/pt30m, 20101030t061500z/pt30m, 20101130t061500z/pt30m, 20101230t061500z/pt30m] */ }
but if use same library small change:
rrule('freq=monthly;until=20110101')
-->
rrule('freq=monthly;until=20110101;bymonthday=31')
it calculated correctly. need same calculation both cases because of rfc5545.
the root issue in ical4j in recur.java
:
private void increment(final calendar cal) { final int calinterval = (getinterval() >= 1) ? getinterval() : 1; cal.add(calincfield, calinterval); }
java.time
use modern java.time classes rather troublesome old legacy classes.
your question overwrought , unclear. here general pointers , examples should going in right direction.
the localdate
class represents date-only value without time-of-day , without time zone.
localdate ld = localdate.now( zoneid.of( "america/montreal" ) ) ;
if want add month, call plusmonths
.
localdate monthlater = ld.plusmonths( 1 ) ;
if want add 30 days, call plusdays
.
localdate thirtydayslater = ld.plusdays( 30 ) ;
if want last day of next month, use temporaladjuster
first of next month, end of day’s month. find such implementations in temporaladjusters
class (note plural s
).
localdate firstofnextmonth = ld.with( temporaladjusters.firstofnextmonth() ) ; localdate lastofnextmonth = firstofnextmonth.with( temporaladjusters.lastofmonth() ) ;
if care months happen have 31 days, use month
enum determine length. consider writing own implementation of temporaladjuster
, "lastofthenextmonthcontaining31days".
if( ld.getmonth().maxlength() == 31 ) { … }
if want day of every month, use yearmonth
class. trap datetimeexception
if month lacks day-of-month such 31 in february.
yearmonth ym = yearmonth.from( ld ) ; localdate thirteenth = ym.atday( 13 ) ;
get same day-of-month in following month.
int dayofmonth = ld.getdayofmonth() ; yearmonth = yearmonth.from( ld ) ; localdate samedayofmonthinnextmonth = ym.plusmonths( 1 ).atday( dayofmonth ) ;
if needed, can add time-of-day , time zone zoneddatetime
. if time-of-day happens invalid in date, automatically adjusted. sure study adjustment behavior see agrees needs.
localtime lt = localtime.of( 9 , 30 ) ; zoneid z = zoneid.of( "pacific/auckland" ) ; zoneddatetime zdt = zoneddatetime.of( ld , lt , z ) ;
Comments
Post a Comment