2005/5/9

     
 

SimpleCalendar.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/SimpleCalendar.cpp,v 1.7 2005/02/05 10:45:06 kommer Exp $


#include "SimpleCalendar.h"

namespace acdk {
namespace util {



namespace {

const int MinYear = -4799;
const int DaysPerYear        = 365;
const int DaysPerLeapYear    = 366;


static const int MonthDaysTable[ 2 ][ 12 ] =
  {
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
  };

const long day_of_year_offset = 31738;

enum Month 
{
  January = 1,
  February = 2,
  March = 3,
  April = 4,
  May = 5,
  June = 6,
  July = 7,
  August = 8,
  September = 9,
  October = 10,
  November = 11,
  December = 12
};

} // anon namespace

bool 
SimpleCalendar::isLeapYear(int year)
{
  if (year < 0)
    ++year;
  return (year % 100) ? (year % 4 == 0) : (year % 400 == 0);
}

bool 
SimpleCalendar::equals(IN(acdk::lang::Object) obj)
{
  if (instanceof(obj, SimpleCalendar) == false)
    return false;
  RSimpleCalendar rs(obj);
  return getJulianDay() == rs->getJulianDay() 
      && getMillisecondsOfDay() == rs->getMillisecondsOfDay();
}

//static 
int 
SimpleCalendar::monthDayCount(int year, int month)
{
   
  int ergday;
  bool isleap = isLeapYear(year);
  switch ( month ) {
    case February:
      ergday =  28;
      if (isleap == true)
         ergday += 1;
      break;
    case April:
    case June:
    case September:
    case November:
      ergday = 30;
      break;
    default:
      ergday = 31;
  }
  return ergday;
}



//static 
int 
SimpleCalendar::toJulianDay(int year, int month, int day)
{
  
  
  int day_of_year = day - 1 ;
  // Adjust for BC and normalize
  
  long tyear = year + ( year < 0 ) - MinYear;

  if ( tyear ) {
    day_of_year += ( tyear / 400 ) * 146097L; // + 365L;
    tyear %= 400;

    day_of_year += ( tyear / 100 ) * 36524L;
    tyear %= 100;

    // days in 4 years
    day_of_year += ( tyear / 4 ) * 1461L;
    tyear %= 4;

    // remaining years
    day_of_year += tyear * 365L;
  }
  
   
  day_of_year += MonthDaysTable[(isLeapYear( year ) ? 1 : 0)][month - 1];

  return day_of_year - day_of_year_offset;
}

void 
SimpleCalendar::fromJulianDay( int jday
                        , int* yp
                        , int* mp
                        , int* dp)
{
   jday += day_of_year_offset;
   int year = 0L;

   if (jday >= DaysPerYear) {
      // Days in 400 years.
      year += 400 * ( jday / 146097L );
      jday %= 146097L;
      
      
      int rest_years = jday / 36524L;
      
      if ( rest_years > 3 )
         rest_years = 3;
      year += 100L * rest_years;
      jday -= 36524L * rest_years;
      
      
      year += 4L * ( jday / 1461L );
      jday %= 1461L;
      
      rest_years = ( jday / 365L );
      
      if ( rest_years > 3 )
         rest_years = 3;
      
      year += rest_years;
      jday -= DaysPerYear * rest_years;
   }

  // Adjust year.
  year += MinYear;

  if ( year <= 0 )
    year--;

  // Find month.
  int month = 1;
  while ( true ) 
  {
    int d = monthDayCount( month, year );

    if (jday < d)
      break;

    jday -= d;
    month++;
  }
  if ( mp )
    *mp = month;

  if ( dp )
    *dp =  jday;

  if ( yp )
    *yp = year;
}

} // util
} // acdk