日期范围内的日期范围
实际上,这项任务对我来说似乎很容易,但我有点卡住了,希望能得到一些提示:D
我有一些活动的开始和结束时间 - 我想创建一个包含日历周的表格.
因此我写了一个方法来检查一个事件是否在这周内,像这样给它着色:
private boolean inWeek(Date date, Entry pe) {return ((pe.getStartsAt().after(Util.firstDayOfWeek(date)) || pe.getStartsAt().equals(Util.firstDayOfWeek(date)))&&(pe.getEndsAt().before(Util.lastDayOfWeek(date)) || pe.getEndsAt().equals(Util.lastDayOfWeek(date))));}
如果事件只持续一周,这个案例还可以.但是如果活动在本周之前开始,或者在本周之后结束,甚至持续数周呢?
它变得非常复杂,我目前的解决方案是这样的:
private boolean inWeek(Date date, Entry pe) {return ( pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().before(Util.lastDayOfWeek(日期)) )||( pe.getStartsAt().before(Util.lastDayOfWeek(date)) && pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.lastDayOfWeek(日期)) )||( pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().before(Util.lastDayOfWeek(date)) )||( pe.getStartsAt().before(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.lastDayOfWeek(date)) );}
但在某些单元格中仍然没有显示正确的颜色.有人对我有任何提示吗?
(...不建议joda times ^^)
解决方案Joda-Time
的默认时区.因此,此应用程序在部署到设置为其他时区的其他机器时会得到不同的结果.使用正确的时区名称,不要使用三字母代码.
如果您的应用适用于跨时区的人和地点,您应该考虑将目标周基于 UTC/GMT(无时区偏移).请注意,这就是 StackOverflow 在每天跟踪您的活动时所做的.日"由 UTC/GMT 定义.
这些点证明了为什么您不应该使用自己的日期时间逻辑.改用有能力的图书馆.在 Java 中,这意味着 Joda-Time 或新的 java.time.* 类Java 8(受 Joda-Time 启发).
ISO 周
顺便说一下,ISO 8601 标准准确地定义了周".各国越来越多的公司和行业正在采用该标准.遵循该标准可能会证明是有用的.Joda-Time DateTime 实例知道其 ISO 周数.调用 myDateTime.weekOfWeakYear().get()
.
示例代码
DateTimeZone timeZone = DateTimeZone.forID("Europe/Berlin");间隔 weekInQuestion = 新间隔(新日期时间(2014, 1, 20, 3, 4, 5, timeZone).withTimeAtStartOfDay(), 新日期时间(2014, 1, 27, 3, 4, 5, timeZone).withTimeAtStartOfDay());间隔 i1 = 新间隔(新日期时间(2014、1、2、3、4、5、时区)、新日期时间(2014、1、3、23、4、5、时区));间隔 i2 = 新间隔(新日期时间(2014, 1, 24, 3, 4, 5, 时区),新日期时间(2014, 1, 26, 23, 59, 59, 时区));间隔 i3 = 新间隔(新日期时间(2014, 1, 6, 3, 4, 5, timeZone),新日期时间(2014, 1, 30, 3, 4, 5, timeZone));boolean i1HitsWeekInQuestion = i1.overlaps(weekInQuestion);boolean i2HitsWeekInQuestion = i2.overlaps(weekInQuestion);boolean i3HitsWeekInQuestion = i3.overlaps(weekInQuestion);
转储到控制台...
System.out.println("weekInQuestion:" + weekInQuestion);System.out.println("i1: " + i1 + " 命中周数:" + i1HitsWeekInQuestion );System.out.println("i2: " + i2 + " 命中周数:" + i2HitsWeekInQuestion );System.out.println("i3: " + i3 + " 命中周数:" + i3HitsWeekInQuestion );
运行时……
weekInQuestion: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00i1:2014-01-02T03:04:05.000+01:00/2014-01-03T23:04:05.000+01:00 点击周:假i2: 2014-01-24T03:04:05.000+01:00/2014-01-26T23:59:59.000+01:00 点击周数: truei3: 2014-01-06T03:04:05.000+01:00/2014-01-30T03:04:05.000+01:00 点击周数: true
Actually this task seemed very easy to me, but i got a little bit stuck and would be thankful for some hints :D
I have some events with a start and an end time - and i would like to create a table with calendar weeks.
Therefore i wrote a method to to check if an event is within this week to color it like this:
private boolean inWeek(Date date, Entry pe) {
return ((pe.getStartsAt().after(Util.firstDayOfWeek(date)) || pe.getStartsAt().equals(Util.firstDayOfWeek(date)))
&& (pe.getEndsAt().before(Util.lastDayOfWeek(date)) || pe.getEndsAt().equals(Util.lastDayOfWeek(date))));
}
This case was okay if events are just lasting one week. but what if the event starts before this week, or ends after this week or even lasts several weeks?
it became very complicated and my current solution was this:
private boolean inWeek(Date date, Entry pe) {
return ( pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().before(Util.lastDayOfWeek(date)) )
|| ( pe.getStartsAt().before(Util.lastDayOfWeek(date)) && pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.lastDayOfWeek(date)) )
|| ( pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().before(Util.lastDayOfWeek(date)) )
|| ( pe.getStartsAt().before(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.lastDayOfWeek(date)) );
}
but thas still not showing the right coloration in some cells. Does anybody have any hints for me?
(...without proposing joda times ^^)
解决方案Joda-Time
The Joda-Time 2.3 library makes this work much easier. It includes an Interval class with an overlap
method.
See the answer by MadProgrammer for similar code and discussion.
Key Points
The Interval class is smart, considering the beginning of interval to be inclusive and the ending exclusive. You should make comparisons based on the logic of EQUAL TO OR GREATER THAN the start but LESS THAN the stop. Why? Because the moment before the new day is infinitely divisible. You may think, "Well java.util.Date & Joda-Time resolve to milliseconds so I'll use .999". But then you'll be surprised when you port code to Java 8's new java.time.* classes where time resolves to nanoseconds.
To support this comparison, notice that the target week is defined with a call to withTimeAtStartOfDay
. Use this method rather than trying to create a midnight by setting zero time elements. This method is smart and handles Daylight Saving Time and other anomalies where there may not be a 00:00:00 midnight time on certain days in certain time zones.
Specify a time zone rather than rely on defaults. All the code in other answers fail to address the time zone. That means they use the default time zone of the JVM. As a consequence, this app gets different results when deployed to other machines set to other time zones. Use proper time zone names, never 3-letter codes.
If your app applies to people and places across time zones, you should consider basing the target week on UTC/GMT (no time zone offset). Notice that is what StackOverflow does in tracking your activity day by day. A "day" is defined by UTC/GMT.
These points are evidence why you should not roll your own date-time logic. Use a competent library instead. In Java, that means either Joda-Time or the new java.time.* classes in Java 8 (inspired by Joda-Time).
ISO Week
By the way, the ISO 8601 standard defines a "week" precisely. More companies and industries in various countries are adopting this standard. Following that standard may prove useful. A Joda-Time DateTime instance knows its ISO week number. Call myDateTime.weekOfWeakYear().get()
.
Example Code
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Berlin" );
Interval weekInQuestion = new Interval( new DateTime( 2014, 1, 20, 3, 4, 5, timeZone ).withTimeAtStartOfDay(), new DateTime( 2014, 1, 27, 3, 4, 5, timeZone ).withTimeAtStartOfDay() );
Interval i1 = new Interval( new DateTime( 2014, 1, 2, 3, 4, 5, timeZone ), new DateTime( 2014, 1, 3, 23, 4, 5, timeZone ) );
Interval i2 = new Interval( new DateTime( 2014, 1, 24, 3, 4, 5, timeZone ), new DateTime( 2014, 1, 26, 23, 59, 59, timeZone ) );
Interval i3 = new Interval( new DateTime( 2014, 1, 6, 3, 4, 5, timeZone ), new DateTime( 2014, 1, 30, 3, 4, 5, timeZone ) );
boolean i1HitsWeekInQuestion = i1.overlaps( weekInQuestion );
boolean i2HitsWeekInQuestion = i2.overlaps( weekInQuestion );
boolean i3HitsWeekInQuestion = i3.overlaps( weekInQuestion );
Dump to console…
System.out.println( "weekInQuestion: " + weekInQuestion );
System.out.println( "i1: " + i1 + " hits week: " + i1HitsWeekInQuestion );
System.out.println( "i2: " + i2 + " hits week: " + i2HitsWeekInQuestion );
System.out.println( "i3: " + i3 + " hits week: " + i3HitsWeekInQuestion );
When run…
weekInQuestion: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00
i1: 2014-01-02T03:04:05.000+01:00/2014-01-03T23:04:05.000+01:00 hits week: false
i2: 2014-01-24T03:04:05.000+01:00/2014-01-26T23:59:59.000+01:00 hits week: true
i3: 2014-01-06T03:04:05.000+01:00/2014-01-30T03:04:05.000+01:00 hits week: true
相关文章