// 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.util; import com.google.ical.values.DateTimeValue; import com.google.ical.values.DateTimeValueImpl; import com.google.ical.values.DateValue; import com.google.ical.values.DateValueImpl; import com.google.ical.util.TimeUtils; import com.google.ical.values.TimeValue; /** * a mutable buffer that can be used to build {@link DateValue}s and * {@link DateTimeValue}s. * * @author mikesamuel+svn@gmail.com (Mike Samuel) */ public class DTBuilder { /** in AD. 0 -> 1BC. */ public int year; /** one indexed. */ public int month; /** one indexed */ public int day; /** zero indexed in 24 hour time. */ public int hour; /** zero indexed */ public int minute; /** zero indexed */ public int second; public DTBuilder(int year, int month, int day, int hour, int minute, int second) { this.year = year; this.month = month; this.day = day; this.hour = hour; this.minute = minute; this.second = second; } public DTBuilder(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public DTBuilder(DateValue dv) { this.year = dv.year(); this.month = dv.month(); this.day = dv.day(); if (dv instanceof TimeValue) { TimeValue tv = (TimeValue) dv; this.hour = tv.hour(); this.minute = tv.minute(); this.second = tv.second(); } } /** * produces a normalized date time, using zero for the time fields if none * were provided. * @return not null */ public DateTimeValue toDateTime() { normalize(); return new DateTimeValueImpl(year, month, day, hour, minute, second); } /** * produces a normalized date. * @return not null */ public DateValue toDate() { normalize(); return new DateValueImpl(year, month, day); } /** * behavior undefined unless normalized. * If you're not sure whether it's appropriate to use this method, use * <code>toDateValue().compareTo(dv)</code> instead. */ public int compareTo(DateValue dv) { long dvComparable = (((((long) dv.year()) << 4) + dv.month()) << 5) + dv.day(); long dtbComparable = ((((long) year << 4) + month << 5)) + day; if (dv instanceof TimeValue) { TimeValue tv = (TimeValue) dv; dvComparable = (((((dvComparable << 5) + tv.hour()) << 6) + tv.minute()) << 6) + tv.second(); dtbComparable = (((((dtbComparable << 5) + hour) << 6) + minute) << 6) + second; } long delta = dtbComparable - dvComparable; return delta < 0 ? -1 : delta == 0 ? 0 : 1; } /** * makes sure that the fields are in the proper ranges, by e.g. converting * 32 January to 1 February, or month 0 to December of the year before. */ public void normalize() { this.normalizeTime(); this.normalizeDate(); } @Override public String toString() { return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second; } @Override public boolean equals(Object o) { if (!(o instanceof DTBuilder)) { return false; } DTBuilder that = (DTBuilder) o; return this.year == that.year && this.month == that.month && this.day == that.day && this.hour == that.hour && this.minute == that.minute && this.second == that.second; } @Override public int hashCode() { return ((((((((year << 4) + month << 5) + day) << 5) + hour) << 6) + minute) << 6) + second; } private void normalizeTime() { int addMinutes = ((second < 0) ? (second - 59) : second) / 60; second -= addMinutes * 60; minute += addMinutes; int addHours = ((minute < 0) ? (minute - 59) : minute) / 60; minute -= addHours * 60; hour += addHours; int addDays = ((hour < 0) ? (hour - 23) : hour) / 24; hour -= addDays * 24; day += addDays; } private void normalizeDate() { while (day <= 0) { int days = TimeUtils.yearLength(month > 2 ? year : year - 1); day += days; --year; } if (month <= 0) { int years = month / 12 - 1; year += years; month -= 12 * years; } else if (month > 12) { int years = (month - 1) / 12; year += years; month -= 12 * years; } while (true) { if (month == 1) { int yearLength = TimeUtils.yearLength(year); if (day > yearLength) { ++year; day -= yearLength; } } int monthLength = TimeUtils.monthLength(year, month); if (day > monthLength) { day -= monthLength; if (++month > 12) { month -= 12; ++year; } } else { break; } } } }