在给定开始日期,结束日期和周期性的情况下,是否可以使用Joda Time获取间隔列表?
每周期间的示例:
* start date: WED 2017-03-01 00:00
* end date: TUE 2017-03-14 00:00
* periodicity: MON 04:00 - WED 06:00
结果应该是适合开始和结束日期的所有时段,因此根据示例:
WED 2017-03-01 00:00 - WED 2017-03-01 06:00
MON 2017-03-06 04:00 - WED 2017-03-08 06:00
MON 2017-03-13 04:00 - TUE 2017-03-14 00:00
有没有人知道如何在Joda Time中这样做?最好是通用的,i。即与其他类型的期间,如每日/每周/每月/每年/等。
非常感谢您的专业知识!
答案 0 :(得分:0)
在深入了解Joda Time后,我自己找到了解决方案。我在这里发布,也许其他人也需要它。如果有人对Joda Time更熟悉,请随时改进代码。
算法:
我真的不想做自己的计算,所以算法只使用api,因此可以使用优化(例如for循环来获取星期几)。
所以如果有人需要代码,这里是:
Periodicity.java
import org.joda.time.DurationFieldType;
/**
* Supported periodicity: daily, weekly, yearly, week of year
*/
public enum Periodicity {
DAILY( DurationFieldType.days(), 1),
WEEKLY( DurationFieldType.weeks(), 1),
YEARLY( DurationFieldType.years(), 1),
WEEK_OF_YEAR( DurationFieldType.weekyears(), 1),
;
DurationFieldType durationFieldType;
int durationAmount;
private Periodicity( DurationFieldType durationFieldType, int durationAmount) {
this.durationFieldType = durationFieldType;
this.durationAmount = durationAmount;
}
public DurationFieldType getDurationFieldType() {
return durationFieldType;
}
public int getDurationAmount() {
return durationAmount;
}
}
IntervalCreator.java
import java.util.ArrayList;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.DateTimeFieldType;
import org.joda.time.DateTimeZone;
import org.joda.time.DurationFieldType;
import org.joda.time.Interval;
import org.joda.time.MutableDateTime;
import org.joda.time.Partial;
public class IntervalCreator {
MutableDateTime startInstant;
MutableDateTime endInstant;
Partial startPartial;
Partial endPartial;
DurationFieldType durationFieldType;
int durationAmount;
MutableDateTime mutableStartInstant;
MutableDateTime mutableEndInstant;
public IntervalCreator(DateTime startInstant, DateTime endInstant, Partial startPartial, Partial endPartial, Periodicity periodicity) {
this.startInstant = new MutableDateTime(startInstant, DateTimeZone.UTC);
this.endInstant = new MutableDateTime(endInstant, DateTimeZone.UTC);
this.startPartial = startPartial;
this.endPartial = endPartial;
this.durationFieldType = periodicity.getDurationFieldType();
this.durationAmount = periodicity.getDurationAmount();
}
/**
* Apply partial datetime to given instant
* @param mutableInstant
* @param partial
*/
private void applyPartial(MutableDateTime mutableInstant, Partial partial) {
for (int i = 0; i < partial.getFields().length; i++) {
DateTimeFieldType fieldType = partial.getFieldTypes()[i];
if (fieldType == DateTimeFieldType.dayOfWeek()) {
// find day of week by going backwards in time
// in opposite to DateTime the MutableDateTime doesn't have a withDayOfWeek() method
int dayOfWeek = partial.getValue(i);
while (mutableInstant.getDayOfWeek() != dayOfWeek) {
mutableInstant.addDays(-1);
}
} else if (fieldType == DateTimeFieldType.minuteOfDay()) {
mutableInstant.setMinuteOfHour(partial.getValue(i));
} else if (fieldType == DateTimeFieldType.hourOfDay()) {
mutableInstant.setHourOfDay(partial.getValue(i));
} else if (fieldType == DateTimeFieldType.dayOfMonth()) {
mutableInstant.setDayOfMonth(partial.getValue(i));
} else if (fieldType == DateTimeFieldType.monthOfYear()) {
mutableInstant.setMonthOfYear(partial.getValue(i));
} else if (fieldType == DateTimeFieldType.weekOfWeekyear()) {
mutableInstant.setWeekOfWeekyear(partial.getValue(i));
mutableInstant.setDayOfWeek(DateTimeConstants.MONDAY); // reset weekday to monday
} else {
throw new IllegalArgumentException("Illegal DateTimeFieldType: " + fieldType);
}
}
}
/**
* Add specified duration
* @param instant
*/
private void nextInstant(MutableDateTime instant) {
addDuration( instant, durationAmount);
}
/**
* Subtract specified duration
* @param instant
*/
private void previousInstant(MutableDateTime instant) {
addDuration( instant, -durationAmount);
}
/**
* Convenience method to add a duration to an instant
* @param instant
* @param amount
*/
private void addDuration(MutableDateTime instant, int amount) {
if (durationFieldType == DurationFieldType.days()) {
instant.addDays(amount);
} else if (durationFieldType == DurationFieldType.weeks()) {
instant.addWeeks(amount);
} else if (durationFieldType == DurationFieldType.years()) {
instant.addYears(amount);
} else if (durationFieldType == DurationFieldType.weekyears()) {
instant.addWeekyears(amount);
} else {
throw new IllegalArgumentException("Illegal duration field type: " + durationFieldType);
}
}
/**
* Create interval slices
* @return
*/
public List<Interval> createIntervals() {
this.mutableStartInstant = new MutableDateTime(startInstant, DateTimeZone.UTC);
this.mutableEndInstant = new MutableDateTime(endInstant, DateTimeZone.UTC);
applyPartial(mutableStartInstant, startPartial);
applyPartial(mutableEndInstant, endPartial);
List<Interval> list = new ArrayList<>();
// search previous valid start date before the global start date
while (mutableStartInstant.isAfter(startInstant)) {
previousInstant(mutableStartInstant);
}
// search previous valid end date
while (mutableEndInstant.isAfter(startInstant)) {
previousInstant(mutableEndInstant);
}
// correct the end date in case it is before the start date (e. g. if
// you have 22:00 - 02:00; or 00:00 - 00:00)
if (mutableEndInstant.compareTo(mutableStartInstant) <= 0) {
nextInstant(mutableEndInstant);
}
// advance in period steps until the local start date exceeds the
// global end date
while (mutableStartInstant.compareTo(endInstant) < 0) {
// clip local start date at global start date bounds, if
// necessary
MutableDateTime clippedStartDate = mutableStartInstant;
if (mutableStartInstant.compareTo(startInstant) <= 0 && mutableEndInstant.compareTo(startInstant) >= 0) {
clippedStartDate = startInstant;
}
// clip local end date at global end date bounds, if necessary
MutableDateTime clippedEndDate = mutableEndInstant;
if (mutableStartInstant.compareTo(endInstant) <= 0 && mutableEndInstant.compareTo(endInstant) >= 0) {
clippedEndDate = endInstant;
}
// create period; ensure the interval is valid (it might not be
// if the initial interval is entirely before the global start date
if (clippedStartDate.compareTo(startInstant) >= 0 && clippedEndDate.compareTo(endInstant) <= 0) {
Interval period = new Interval(clippedStartDate, clippedEndDate);
list.add(period);
}
// next duration
nextInstant(mutableStartInstant);
nextInstant(mutableEndInstant);
}
return list;
}
}
和一个测试类
JodaTimeTest.java
import java.util.List;
import java.util.Locale;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.DateTimeFieldType;
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
import org.joda.time.Partial;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class JodaTimeTest {
public static DateTimeFormatter formatter = DateTimeFormat.forPattern("w E yyyy-MM-dd HH:mm");
public static List<Interval> createDailyPeriod() {
DateTime startInstant = new DateTime(2017, 3, 22, 0, 0, 0, 0, DateTimeZone.UTC);
DateTime endInstant = new DateTime(2017, 3, 30, 0, 0, 0, 0, DateTimeZone.UTC);
DateTimeFieldType[] fields = new DateTimeFieldType[] { DateTimeFieldType.hourOfDay(), DateTimeFieldType.minuteOfDay() };
Partial startPartial = new Partial( fields, new int[] { 23, 0 });
Partial endPartial = new Partial( fields, new int[] { 2, 0 });
IntervalCreator intervalCreator = new IntervalCreator(startInstant, endInstant, startPartial, endPartial, Periodicity.DAILY);
List<Interval> intervals = intervalCreator.createIntervals();
log(intervals);
return intervals;
}
public static List<Interval> createWeeklyPeriod() {
DateTime startInstant = new DateTime(2017, 3, 1, 0, 0, 0, 0, DateTimeZone.UTC);
DateTime endInstant = new DateTime(2017, 3, 14, 0, 0, 0, 0, DateTimeZone.UTC);
DateTimeFieldType[] fields = new DateTimeFieldType[] { DateTimeFieldType.dayOfWeek(), DateTimeFieldType.hourOfDay(), DateTimeFieldType.minuteOfDay() };
Partial startPartial = new Partial(fields, new int[] { DateTimeConstants.MONDAY, 4, 0 });
Partial endPartial = new Partial(fields, new int[] { DateTimeConstants.WEDNESDAY, 6, 0 });
IntervalCreator intervalCreator = new IntervalCreator(startInstant, endInstant, startPartial, endPartial, Periodicity.WEEKLY);
List<Interval> intervals = intervalCreator.createIntervals();
log(intervals);
return intervals;
}
public static List<Interval> createYearlyPeriod() {
DateTime startInstant = new DateTime(2012, 3, 1, 0, 0, 0, 0, DateTimeZone.UTC);
DateTime endInstant = new DateTime(2017, 3, 14, 0, 0, 0, 0, DateTimeZone.UTC);
DateTimeFieldType[] fields = new DateTimeFieldType[] { DateTimeFieldType.monthOfYear(), DateTimeFieldType.dayOfMonth(), DateTimeFieldType.hourOfDay(), DateTimeFieldType.minuteOfDay() };
Partial startPartial = new Partial(fields, new int[] { 2, 27, 4, 0 });
Partial endPartial = new Partial(fields, new int[] { 3, 16, 6, 0 });
IntervalCreator intervalCreator = new IntervalCreator(startInstant, endInstant, startPartial, endPartial, Periodicity.YEARLY);
List<Interval> intervals = intervalCreator.createIntervals();
log(intervals);
return intervals;
}
public static List<Interval> createYearlyPeriodByCalendarWeek() {
DateTime startInstant = new DateTime(2012, 3, 1, 0, 0, 0, 0, DateTimeZone.UTC);
DateTime endInstant = new DateTime(2017, 1, 10, 0, 0, 0, 0, DateTimeZone.UTC);
DateTimeFieldType[] fields = new DateTimeFieldType[] { DateTimeFieldType.weekOfWeekyear(), DateTimeFieldType.hourOfDay(), DateTimeFieldType.minuteOfDay() };
Partial startPartial = new Partial(fields, new int[] { 1, 2, 0 });
Partial endPartial = new Partial(fields, new int[] { 3, 6, 0 });
IntervalCreator intervalCreator = new IntervalCreator(startInstant, endInstant, startPartial, endPartial, Periodicity.WEEK_OF_YEAR);
List<Interval> intervals = intervalCreator.createIntervals();
log(intervals);
return intervals;
}
private static void log(List<Interval> intervals) {
for (int i = 0; i < intervals.size(); i++) {
Interval interval = intervals.get(i);
System.out.println("Interval " + i + ": " + formatter.print(interval.getStart()) + " - " + formatter.print(interval.getEnd()));
}
}
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
System.out.println("daily:");
createDailyPeriod();
System.out.println("\nweekly:");
createWeeklyPeriod();
System.out.println("\nyearly:");
createYearlyPeriod();
System.out.println("\nyearly by calendar week:");
createYearlyPeriodByCalendarWeek();
System.exit(0);
}
}
测试输出:
daily:
Interval 0: 12 Wed 2017-03-22 00:00 - 12 Wed 2017-03-22 02:00
Interval 1: 12 Wed 2017-03-22 23:00 - 12 Thu 2017-03-23 02:00
Interval 2: 12 Thu 2017-03-23 23:00 - 12 Fri 2017-03-24 02:00
Interval 3: 12 Fri 2017-03-24 23:00 - 12 Sat 2017-03-25 02:00
Interval 4: 12 Sat 2017-03-25 23:00 - 12 Sun 2017-03-26 02:00
Interval 5: 12 Sun 2017-03-26 23:00 - 13 Mon 2017-03-27 02:00
Interval 6: 13 Mon 2017-03-27 23:00 - 13 Tue 2017-03-28 02:00
Interval 7: 13 Tue 2017-03-28 23:00 - 13 Wed 2017-03-29 02:00
Interval 8: 13 Wed 2017-03-29 23:00 - 13 Thu 2017-03-30 00:00
weekly:
Interval 0: 9 Wed 2017-03-01 00:00 - 9 Wed 2017-03-01 06:00
Interval 1: 10 Mon 2017-03-06 04:00 - 10 Wed 2017-03-08 06:00
Interval 2: 11 Mon 2017-03-13 04:00 - 11 Tue 2017-03-14 00:00
yearly:
Interval 0: 9 Thu 2012-03-01 00:00 - 11 Fri 2012-03-16 06:00
Interval 1: 9 Wed 2013-02-27 04:00 - 11 Sat 2013-03-16 06:00
Interval 2: 9 Thu 2014-02-27 04:00 - 11 Sun 2014-03-16 06:00
Interval 3: 9 Fri 2015-02-27 04:00 - 12 Mon 2015-03-16 06:00
Interval 4: 8 Sat 2016-02-27 04:00 - 11 Wed 2016-03-16 06:00
Interval 5: 9 Mon 2017-02-27 04:00 - 11 Tue 2017-03-14 00:00
yearly by calendar week:
Interval 0: 1 Mon 2012-12-31 02:00 - 3 Mon 2013-01-14 06:00
Interval 1: 1 Mon 2013-12-30 02:00 - 3 Mon 2014-01-13 06:00
Interval 2: 1 Mon 2014-12-29 02:00 - 3 Mon 2015-01-12 06:00
Interval 3: 1 Mon 2016-01-04 02:00 - 3 Mon 2016-01-18 06:00
Interval 4: 1 Mon 2017-01-02 02:00 - 2 Tue 2017-01-10 00:00