2005/5/9

     
 

SimpleTimeZone.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/util/SimpleTimeZone.cpp,v 1.12 2005/03/08 12:45:46 kommer Exp $

#include <acdk.h>
#include "SimpleTimeZone.h"
#include <acdk/lang/UnsupportedOperationException.h>
#include <acdk/lang/Integer.h>
#include <acdk/util/GregorianCalendar.h>

namespace acdk {
namespace util {

const int SimpleTimeZone::DOM_MODE = 1;
const int SimpleTimeZone::DOW_IN_MONTH_MODE = 2;
const int SimpleTimeZone::DOW_GE_DOM_MODE = 3;
const int SimpleTimeZone::DOW_LE_DOM_MODE= 4;

SimpleTimeZone::SimpleTimeZone() 
  : TimeZone(),
    _dstSavings(60*60*1000)
{
}

SimpleTimeZone::SimpleTimeZone(int rOs, IN(RString) id)
  : TimeZone(id),
    _rawOffset(rOs),
    _useDayLight(false),
    _dstSavings(60*60*1000),
    _startYear(0)
{
}

SimpleTimeZone::SimpleTimeZone(int rOs, IN(RString) id, 
                               int startMonth, int startDayOfWeekInMonth, 
                               int startDayOfWeek, int startTime,
                               int endMonth, int endDayOfWeekInMonth,
                               int endDayOfWeek, int endTime)
  : TimeZone(id),
    _rawOffset(rOs),
    _useDayLight(false),
    _dstSavings(60*60*1000)
{
  setStartRule(startMonth, startDayOfWeekInMonth, 
               startDayOfWeek, startTime);
  setEndRule(endMonth, endDayOfWeekInMonth, 
             endDayOfWeek, endTime);

  if (endDayOfWeek == 0)
    _endMode = DOM_MODE;
  else if (endDayOfWeek > 0)
    _endMode = DOW_IN_MONTH_MODE;
  else if (endDayOfWeek < 0) {
    endDayOfWeek = -endDayOfWeek;
    if (_endDay < 0){
      _endDay = -_endDay;
      _endMode = DOW_LE_DOM_MODE;
    } else
      _endMode = DOW_GE_DOM_MODE;
  }
  
  _endMonth =  endMonth;
  _endDay = endDayOfWeekInMonth;
  _endDayOfWeek = endDayOfWeek;
  _endTime = endTime;
  _startYear = 0;

}

SimpleTimeZone::SimpleTimeZone(int rOs, IN(RString) id, 
                               int startMonth, int startDayOfWeekInMonth, 
                               int startDayOfWeek, int startTime,
                               int endMonth, int endDayOfWeekInMonth,
                               int endDayOfWeek, int endTime,
                               int dstSavings)
  : TimeZone(id),
    _rawOffset(rOs),
    _useDayLight(false),
    _dstSavings(dstSavings)
{
  setStartRule(startMonth, startDayOfWeekInMonth, 
               startDayOfWeek, startTime);
  setEndRule(endMonth, endDayOfWeekInMonth, 
             endDayOfWeek, endTime);

  if (endDayOfWeek == 0)
    _endMode = DOM_MODE;
  else if (endDayOfWeek > 0)
    _endMode = DOW_IN_MONTH_MODE;
  else if (endDayOfWeek < 0) {
    endDayOfWeek = -endDayOfWeek;
    if (_endDay < 0){
      _endDay = -_endDay;
      _endMode = DOW_LE_DOM_MODE;
    } else
      _endMode = DOW_GE_DOM_MODE;
  }
  
  _endMonth =  endMonth;
  _endDay = endDayOfWeekInMonth;
  _endDayOfWeek = endDayOfWeek;
  _endTime = endTime;
  _startYear = 0;
  
}

SimpleTimeZone::~SimpleTimeZone() 
{
}

void
SimpleTimeZone::setStartRule(int month, int day, int dayOfWeek, int time)
{
  if (dayOfWeek == 0)
    _startMode = DOM_MODE;
  else if (dayOfWeek > 0)
    _startMode = DOW_IN_MONTH_MODE;
  else if (dayOfWeek < 0) {
    dayOfWeek = -dayOfWeek;
    if (day < 0) {
      day = -day;
      _startMode = DOW_LE_DOM_MODE;
    } else 
      _startMode = DOW_GE_DOM_MODE;
  }
  
  _startMonth = month;
  _startDay = day;
  _startDayOfWeek = dayOfWeek;
  _startTime = time;
  _useDayLight = true;
}

void
SimpleTimeZone::setEndRule(int month, int day, int dayOfWeek, int time)
{
  if (dayOfWeek == 0)
    _endMode = DOM_MODE;
  else if (dayOfWeek > 0)
    _endMode = DOW_IN_MONTH_MODE;
  else if (dayOfWeek < 0) {
    dayOfWeek = -dayOfWeek;
    if (day < 0) {
      day = -day;
      _endMode = DOW_LE_DOM_MODE;
    } else 
      _endMode = DOW_GE_DOM_MODE;
  }
  
  _endMonth = month;
  _endDay = day;
  _endDayOfWeek = dayOfWeek;
  _endTime = time;
  _useDayLight = true;
  
}

int 
SimpleTimeZone::getOffset(int era, int year, int month, 
                          int day, int dayOfWeek, int millis)
{
  
  bool daylightSavings;
  if (!_useDayLight || era < GregorianCalendar::AD || era < _startYear)
    daylightSavings = false;
  else if (_startMonth < _endMonth) {
    daylightSavings = !isBefore(year, month, day, dayOfWeek, millis,
                                _startMode, _startMonth, _startDay, _startDayOfWeek, _startTime)
                    && isBefore(year, month, day, dayOfWeek, millis,
                                _endMode, _endMonth, _endDay, _endDayOfWeek, _endTime);
  } else {
    daylightSavings = !isBefore(year, month, day, dayOfWeek, millis,
                                _startMode, _startMonth, _startDay, _startDayOfWeek, _startTime)
                    || isBefore(year, month, day, dayOfWeek, millis,
                                _endMode, _endMonth, _endDay, _endDayOfWeek, _endTime);
  }
  return _rawOffset + (daylightSavings ? _dstSavings : 0);
}

//private
int 
SimpleTimeZone::getDaysInMonth(int month, int year)
{
  if (month == Calendar::FEBRUARY){
    if (year&3 == 0 && (year % 100 != 0 || year % 400 == 0))
      return 29;
    else 
      return 28;
  } else if (month < Calendar::AUGUST)
    return 31 - (month & 1);
  else
    return 30 + (month & 1);
}

//private
bool
SimpleTimeZone::isBefore(int calYear, int calMonth, int calDay, int calDayOfWeek, 
                         int calMillis, int mode, int month, int day,
                         int dayOfWeek, int millis)
{
  
  if (calMonth != month)
    return calMonth < month;

  int week = 0;
  if (mode == DOM_MODE) {
      if (calDay != day)
        return calDay < day;
  } else if (mode ==  DOW_IN_MONTH_MODE ) {
      calDay += (dayOfWeek - calDayOfWeek);
      if (day < 0)
        calDay -= getDaysInMonth(calMonth, calYear)+7;
      else
        calDay += 6;
      week = calDay / 7;
      if (week != day)
        return week < day;
      if (calDayOfWeek != dayOfWeek)
        return calDayOfWeek < dayOfWeek;
  } else if (mode == DOW_LE_DOM_MODE) {
      day -= 6;
  } else if (mode == DOW_GE_DOM_MODE) {
      calDay -= (calDayOfWeek < dayOfWeek ? 7 : 0)  + calDayOfWeek - dayOfWeek;
      if (calDay < day)
        return true;
      if (calDayOfWeek != dayOfWeek || calDay >= day+7)
        return false;
  }
  return (calMillis < millis);
}


RString
SimpleTimeZone::getDisplayName(bool dst, int style, IN(RLocale) locale)
{
  THROW0(UnsupportedOperationException);
  return Nil;
}

int 
SimpleTimeZone::hashCode()
{
  SYNCTHIS();
  int result = 0;
  result = 31 * result + Integer(_rawOffset).hashCode();
  result = 31 * result + Integer(_useDayLight).hashCode();
  result = 31 * result + Integer(_dstSavings).hashCode();
  result = 31 * result + Integer(_startYear).hashCode();
  result = 31 * result + Integer(_startMode).hashCode();
  result = 31 * result + Integer(_startMonth).hashCode();
  result = 31 * result + Integer(_startDay).hashCode();
  result = 31 * result + Integer(_startDayOfWeek).hashCode();
  result = 31 * result + Integer(_startTime).hashCode();
  result = 31 * result + Integer(_endMonth).hashCode();
  result = 31 * result + Integer(_endDay).hashCode();
  result = 31 * result + Integer(_endDayOfWeek).hashCode();
  result = 31 * result + Integer(_endTime).hashCode();
  return result;
}

bool
SimpleTimeZone::equals(IN(acdk::lang::Object) obj)
{
  SYNCTHIS();
  THROW0(UnsupportedOperationException);
  return false;
}

bool 
SimpleTimeZone::inDaylightTime(IN(RDate) date) 
{
  RCalendar cal = Calendar::getInstance((RTimeZone)this);
  cal->setTime(date);
  return cal->get(Calendar::DST_OFFSET) != 0 ;
}

// ##
/*
void 
SimpleTimeZone::writeObject(RObjectOutputWrite output)
{
  THROW0(UnsupportedOperationException);
}

void 
SimpleTimeZone::readObject(RObjectInputWrite input)
{
  THROW0(UnsupportedOperationException);
}
*/

} // Util
} // acdk