// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.ical.iter;
import com.google.ical.values.DateValue;
import com.google.ical.values.TimeValue;
/**
* DateValue comparison methods.
* <p>When we're pulling dates off the priority order, we need them to come off
* in a consistent order, so we need a total ordering on date values.
* <p>This means that a DateValue with no time must not be equal to a
* DateTimeValue at midnight. Since it obviously doesn't make sense for a
* DateValue to be after a DateTimeValue the same day at 23:59:59, we put the
* DateValue before 0 hours of the same day.
* <p>If we didn't have a total ordering, then it would be harder to correctly
* handle the case
* <pre>
* RDATE:20060607
* EXDATE:20060607
* EXDATE:20060607T000000Z
* </pre>
* because we'd have two exdates that are equal according to the comparison, but
* only the first should match.
* <p>In the following example
* <pre>
* RDATE:20060607
* RDATE:20060607T000000Z
* EXDATE:20060607
* </pre>
* the problem is worse because we may pull a candidate RDATE off the
* priority queue and then not know whether to consume the EXDATE or not.
* <p>Absent a total ordering, the following case could only be solved with
* lookahead and ugly logic.
* <pre>
* RDATE:20060607
* RDATE:20060607T000000Z
* EXDATE:20060607
* EXDATE:20060607T000000Z
* </pre>
* <p>The conversion to GMT is also an implementation detail, so it's not clear
* which timezone we should consider midnight in, and a total ordering allows
* us to avoid timezone conversions during iteration.</p>
*
* @author mikesamuel+svn@gmail.com (Mike Samuel)
*/
final class DateValueComparison {
/**
* reduces a date to a value that can be easily compared to others, consistent
* with {@link com.google.ical.values.DateValueImpl#compareTo}.
*/
static long comparable(DateValue dv) {
long comp = (((((long) dv.year()) << 4) + dv.month()) << 5) + dv.day();
if (dv instanceof TimeValue) {
TimeValue tv = (TimeValue) dv;
// We add 1 to comparable for timed values to make sure that timed
// events are distinct from all-day events, in keeping with
// DateValue.compareTo.
// It would be odd if an all day exclusion matched a midnight event on
// the same day, but not one at another time of day.
return (((((comp << 5) + tv.hour()) << 6) + tv.minute()) << 6)
+ tv.second() + 1;
} else {
return comp << 17;
}
}
private DateValueComparison() {
// uninstantiable
}
}