forked from KolibriOS/kolibrios
142 lines
5.3 KiB
C
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 ) );
|
||
|
}
|