kolibrios/programs/develop/open watcom/trunk/clib/time/gmtime.c
Sergey Semyonov (Serge) 3be3768ce0 update CLib
git-svn-id: svn://kolibrios.org@614 a494cfbc-eb01-0410-851d-a64ba20cac60
2007-08-28 10:31:46 +00:00

142 lines
5.3 KiB
C

/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: __brktime() is an internal function to convert time to struct tm
*
****************************************************************************/
#include "variety.h"
#include <time.h>
#include "thetime.h"
#include "timedata.h"
// #define DAYS_IN_4_YRS ( 365 + 365 + 365 + 366 )
// #define DAYS_IN_400_YRS ( ( 100 * DAYS_IN_4_YRS ) - 3 )
// #define SECONDS_PER_DAY ( 24 * 60 * 60 )
// extern short __diyr[], __dilyr[];
/*
The number of leap years from year 1 to year 1900 is 460.
The number of leap years from year 1 to current year is
expressed by "years/4 - years/100 + years/400". To determine
the number of leap years from current year to 1900, we subtract
460 from the formula result. We do this since "days" is the
number of days since 1900.
*/
static unsigned long __DaysToJan1( unsigned year )
{
unsigned years = 1900 + year - 1;
unsigned leap_days = years / 4 - years / 100 + years / 400 - 460;
return( year * 365UL + leap_days );
}
/* __brktime breaks down a calendar time (clock) into a struct tm t */
struct tm *__brktime( unsigned long days,
time_t wallclock,
long gmtdelta, // localtime - gmtime
struct tm *t )
{
unsigned long secs;
unsigned year;
int day_of_year;
int month;
short const *month_start;
/*
If date is Jan 1, 1970 0:00 to 12:00 UTC and we are west of UTC
then add a day to wallclock, subtract the gmtdelta value, and
decrement the calculated days. This prevents local times
such as "Wed Dec 31 19:00:00 1969 (EST)" from being
erroneously reported as "Sun Feb 6 01:28:16 2106 (EST)"
since (wallclock - gmtdelta) wraps (i.e., wallclock < gmtdelta).
*/
if( wallclock < 12 * 60 * 60UL && gmtdelta > 0 )
wallclock += SECONDS_PER_DAY, days--; /* days compensated for wallclock one day ahead */
wallclock -= ( time_t ) gmtdelta;
days += wallclock / SECONDS_PER_DAY;
secs = wallclock % SECONDS_PER_DAY;
t->tm_hour = ( int ) ( secs / 3600 ) ;
secs = secs % 3600;
t->tm_min = ( int ) ( secs / 60 );
t->tm_sec = secs % 60;
// The following two lines are not needed in the current implementation
// because the range of values for days does not exceed DAYS_IN_400_YRS.
// Even if it did, the algorithm still computes the correct values.
//
// unsigned year400s;
//
// year400s = (days / DAYS_IN_400_YRS) * 400;
// days %= DAYS_IN_400_YRS;
//
// It is OK to reduce days to a value less than DAYS_IN_400_YRS, because
// DAYS_IN_400_YRS is exactly divisible by 7. If it wasn't divisible by 7,
// then the following line which appears at the bottom, should be computed
// before the value of days is range reduced.
// t->tm_wday = (days + 1) % 7; /* 24-sep-92 */
//
year = days / 365;
day_of_year = ( int ) ( days - __DaysToJan1( year ) );
while( day_of_year < 0 ) {
--year;
day_of_year += __leapyear( year + 1900 ) + 365;
}
// year += year400s;
t->tm_yday = day_of_year;
t->tm_year = ( int ) year;
month_start = __diyr;
if( __leapyear( year + 1900 ) )
month_start = __dilyr;
month = day_of_year / 31; /* approximate month */
if( day_of_year >= month_start[month + 1] )
++month;
t->tm_mon = month;
t->tm_mday = day_of_year - month_start[month] + 1;
/* Calculate the day of the week */
/* Jan 1,1900 is a Monday */
t->tm_wday = ( days + 1 ) % 7; /* 24-sep-92 */
return( t );
}
_WCRTLINK struct tm *_gmtime( const time_t *timer, struct tm *tm )
{
tm->tm_isdst = 0; /* assume not */
return __brktime( DAYS_FROM_1900_TO_1970, *timer, 0L, tm );
}
_WCRTLINK struct tm *gmtime( const time_t *timer )
{
_INITTHETIME;
return( _gmtime( timer, &_THE_TIME ) );
}