AbstractCalendar.java :  » 6.0-JDK-Modules-sun » util » sun » util » calendar » Java Open Source

Java Open Source » 6.0 JDK Modules sun » util 
util » sun » util » calendar » AbstractCalendar.java
/*
 * Copyright 2003-2004 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package sun.util.calendar;

import java.util.Locale;
import java.util.TimeZone;

/**
 * The <code>AbstractCalendar</code> class provides a framework for
 * implementing a concrete calendar system.
 *
 * <p><a name="fixed_date"></a><B>Fixed Date</B><br>
 *
 * For implementing a concrete calendar system, each calendar must
 * have the common date numbering, starting from midnight the onset of
 * Monday, January 1, 1 (Gregorian). It is called a <I>fixed date</I>
 * in this class. January 1, 1 (Gregorian) is fixed date 1. (See
 * Nachum Dershowitz and Edward M. Reingold, <I>CALENDRICAL
 * CALCULATION The Millennium Edition</I>, Section 1.2 for details.)
 *
 * @author Masayoshi Okutsu
 * @since 1.5
 */

public abstract class AbstractCalendar extends CalendarSystem {

    // The constants assume no leap seconds support.
    static final int SECOND_IN_MILLIS = 1000;
    static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
    static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
    static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;

    // The number of days between January 1, 1 and January 1, 1970 (Gregorian)
    static final int EPOCH_OFFSET = 719163;

    private Era[] eras;

    protected AbstractCalendar() {
    }

    public Era getEra(String eraName) {
  if (eras != null) {
      for (int i = 0; i < eras.length; i++) {
    if (eras[i].equals(eraName)) {
        return eras[i];
    }
      }
  }
  return null;
    }

    public Era[] getEras() {
  Era[] e = null;
  if (eras != null) {
      e = new Era[eras.length];
      System.arraycopy(eras, 0, e, 0, eras.length);
  }
  return e;
    }

    public void setEra(CalendarDate date, String eraName) {
  if (eras == null) {
      return; // should report an error???
  }
  for (int i = 0; i < eras.length; i++) {
      Era e = eras[i];
      if (e != null && e.getName().equals(eraName)) {
    date.setEra(e);
    return;
      }
  }
  throw new IllegalArgumentException("unknown era name: " + eraName);
    }

    protected void setEras(Era[] eras) {
  this.eras = eras;
    }

    public CalendarDate getCalendarDate() {
  return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
    }

    public CalendarDate getCalendarDate(long millis) {
  return getCalendarDate(millis, newCalendarDate());
    }

    public CalendarDate getCalendarDate(long millis, TimeZone zone) {
  CalendarDate date = newCalendarDate(zone);
  return getCalendarDate(millis, date);
    }

    public CalendarDate getCalendarDate(long millis, CalendarDate date) {
  int ms = 0;    // time of day
  int zoneOffset = 0;
  int saving = 0;
  long days = 0;    // fixed date

  // adjust to local time if `date' has time zone.
  TimeZone zi = date.getZone();
  if (zi != null) {
      int[] offsets = new int[2];
      if (zi instanceof ZoneInfo) {
    zoneOffset = ((ZoneInfo)zi).getOffsets(millis, offsets);
      } else {
    zoneOffset = zi.getOffset(millis);
    offsets[0] = zi.getRawOffset();
    offsets[1] = zoneOffset - offsets[0];
      }

      // We need to calculate the given millis and time zone
      // offset separately for java.util.GregorianCalendar
      // compatibility. (i.e., millis + zoneOffset could cause
      // overflow or underflow, which must be avoided.) Usually
      // days should be 0 and ms is in the range of -13:00 to
      // +14:00. However, we need to deal with extreme cases.
      days = zoneOffset / DAY_IN_MILLIS;
      ms = zoneOffset % DAY_IN_MILLIS;
      saving = offsets[1];
  }
  date.setZoneOffset(zoneOffset);
  date.setDaylightSaving(saving);

  days += millis / DAY_IN_MILLIS;
  ms += (int) (millis % DAY_IN_MILLIS);
  if (ms >= DAY_IN_MILLIS) {
      // at most ms is (DAY_IN_MILLIS - 1) * 2.
      ms -= DAY_IN_MILLIS;
      ++days;
  } else {
      // at most ms is (1 - DAY_IN_MILLIS) * 2. Adding one
      // DAY_IN_MILLIS results in still negative.
      while (ms < 0) {
    ms += DAY_IN_MILLIS;
    --days;
      }
  }

  // convert to fixed date (offset from Jan. 1, 1 (Gregorian))
  days += EPOCH_OFFSET;

  // calculate date fields from the fixed date
  getCalendarDateFromFixedDate(date, days);

  // calculate time fields from the time of day
  setTimeOfDay(date, ms);
  date.setLeapYear(isLeapYear(date));
  date.setNormalized(true);
  return date;
    }

    public long getTime(CalendarDate date) {
  long gd = getFixedDate(date);
  long ms = (gd - EPOCH_OFFSET) * DAY_IN_MILLIS + getTimeOfDay(date);
  int zoneOffset = 0;
  TimeZone zi = date.getZone();
  if (zi != null) {
      if (date.isNormalized()) {
    return ms - date.getZoneOffset();
      } 
      // adjust time zone and daylight saving
      int[] offsets = new int[2];
      if (date.isStandardTime()) {
    // 1) 2:30am during starting-DST transition is
    //    intrepreted as 2:30am ST
    // 2) 5:00pm during DST is still interpreted as 5:00pm ST
    // 3) 1:30am during ending-DST transition is interpreted
    //    as 1:30am ST (after transition)
    if (zi instanceof ZoneInfo) {
        ((ZoneInfo)zi).getOffsetsByStandard(ms, offsets);
        zoneOffset = offsets[0];
    } else {
        zoneOffset = zi.getOffset(ms - zi.getRawOffset());
    }
      } else {
    // 1) 2:30am during starting-DST transition is
    //    intrepreted as 3:30am DT
    // 2) 5:00pm during DST is intrepreted as 5:00pm DT
    // 3) 1:30am during ending-DST transition is interpreted
    //    as 1:30am DT/0:30am ST (before transition)
    if (zi instanceof ZoneInfo) {
        zoneOffset = ((ZoneInfo)zi).getOffsetsByWall(ms, offsets);
    } else {
        zoneOffset = zi.getOffset(ms - zi.getRawOffset());
    }
      }
  }
  ms -= zoneOffset;
  getCalendarDate(ms, date);
  return ms;
    }

    protected long getTimeOfDay(CalendarDate date) {
  long fraction = date.getTimeOfDay();
  if (fraction != CalendarDate.TIME_UNDEFINED) {
      return fraction;
  }
  fraction = getTimeOfDayValue(date);
  date.setTimeOfDay(fraction);
  return fraction;
    }

    public long getTimeOfDayValue(CalendarDate date) {
  long fraction = date.getHours();
  fraction *= 60;
  fraction += date.getMinutes();
  fraction *= 60;
  fraction += date.getSeconds();
  fraction *= 1000;
  fraction += date.getMillis();
  return fraction;
    }

    public CalendarDate setTimeOfDay(CalendarDate cdate, int fraction) {
  if (fraction < 0) {
      throw new IllegalArgumentException();
  }
  boolean normalizedState = cdate.isNormalized();
  int time = fraction;
  int hours = time / HOUR_IN_MILLIS;
  time %= HOUR_IN_MILLIS;
  int minutes = time / MINUTE_IN_MILLIS;
  time %= MINUTE_IN_MILLIS;
  int seconds = time / SECOND_IN_MILLIS;
  time %= SECOND_IN_MILLIS;
  cdate.setHours(hours);
  cdate.setMinutes(minutes);
  cdate.setSeconds(seconds);
  cdate.setMillis(time);
  cdate.setTimeOfDay(fraction);
  if (hours < 24 && normalizedState) {
      // If this time of day setting doesn't affect the date,
      // then restore the normalized state.
      cdate.setNormalized(normalizedState);
  }
  return cdate;
    }

    /**
     * Returns 7 in this default implementation.
     *
     * @return 7
     */
    public int getWeekLength() {
  return 7;
    }

    protected abstract boolean isLeapYear(CalendarDate date);

    public CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, CalendarDate date) {
  CalendarDate ndate = (CalendarDate) date.clone();
  normalize(ndate);
  long fd = getFixedDate(ndate);
  long nfd;
  if (nth > 0) {
      nfd = 7 * nth + getDayOfWeekDateBefore(fd, dayOfWeek);
  } else {
      nfd = 7 * nth + getDayOfWeekDateAfter(fd, dayOfWeek);
  }
  getCalendarDateFromFixedDate(ndate, nfd);
  return ndate;
    }

    /**
     * Returns a date of the given day of week before the given fixed
     * date.
     *
     * @param fixedDate the fixed date
     * @param dayOfWeek the day of week
     * @return the calculated date
     */
    static long getDayOfWeekDateBefore(long fixedDate, int dayOfWeek) {
  return getDayOfWeekDateOnOrBefore(fixedDate - 1, dayOfWeek);
    }

    /**
     * Returns a date of the given day of week that is closest to and
     * after the given fixed date.
     *
     * @param fixedDate the fixed date
     * @param dayOfWeek the day of week
     * @return the calculated date
     */
    static long getDayOfWeekDateAfter(long fixedDate, int dayOfWeek) {
  return getDayOfWeekDateOnOrBefore(fixedDate + 7, dayOfWeek);
    }

    /**
     * Returns a date of the given day of week on or before the given fixed
     * date.
     *
     * @param fixedDate the fixed date
     * @param dayOfWeek the day of week
     * @return the calculated date
     */
    // public for java.util.GregorianCalendar
    public static long getDayOfWeekDateOnOrBefore(long fixedDate, int dayOfWeek) {
  long fd = fixedDate - (dayOfWeek - 1);
  if (fd >= 0) {
      return fixedDate - (fd % 7);
  }
  return fixedDate - CalendarUtils.mod(fd, 7);
    }

    /**
     * Returns the fixed date calculated with the specified calendar
     * date. If the specified date is not normalized, its date fields
     * are normalized.
     *
     * @param date a <code>CalendarDate</code> with which the fixed
     * date is calculated
     * @return the calculated fixed date
     * @see AbstractCalendar.html#fixed_date
     */
    protected abstract long getFixedDate(CalendarDate date);

    /**
     * Calculates calendar fields from the specified fixed date. This
     * method stores the calculated calendar field values in the specified
     * <code>CalendarDate</code>.
     *
     * @param date a <code>CalendarDate</code> to stored the
     * calculated calendar fields.
     * @param fixedDate a fixed date to calculate calendar fields
     * @see AbstractCalendar.html#fixed_date
     */
    protected abstract void getCalendarDateFromFixedDate(CalendarDate date,
               long fixedDate);

    public boolean validateTime(CalendarDate date) {
  int t = date.getHours();
  if (t < 0 || t >= 24) {
      return false;
  }
  t = date.getMinutes();
  if (t < 0 || t >= 60) {
      return false;
  }
  t = date.getSeconds();
  // TODO: Leap second support.
  if (t < 0 || t >= 60) {
      return false;
  }
  t = date.getMillis();
  if (t < 0 || t >= 1000) {
      return false;
  }
  return true;
    }


    int normalizeTime(CalendarDate date) {
  long fraction = getTimeOfDay(date);
  long days = 0;

  if (fraction >= DAY_IN_MILLIS) {
      days = fraction / DAY_IN_MILLIS;
      fraction %= DAY_IN_MILLIS;
  } else if (fraction < 0) {
      days = CalendarUtils.floorDivide(fraction, DAY_IN_MILLIS);
      if (days != 0) {
    fraction -= DAY_IN_MILLIS * days; // mod(fraction, DAY_IN_MILLIS)
      }
  }
  if (days != 0) {
      date.setTimeOfDay(fraction);
  }
  date.setMillis((int)(fraction % 1000));
  fraction /= 1000;
  date.setSeconds((int)(fraction % 60));
  fraction /= 60;
  date.setMinutes((int)(fraction % 60));
  date.setHours((int)(fraction / 60));
  return (int)days;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.