📄 dl_time.c
字号:
/******************************************************************************/
/* */
/* Copyright (C) 2004-2007 Oscar Sanderson */
/* */
/* This software is provided 'as-is', without any express or implied */
/* warranty. In no event will the author(s) be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* */
/* 2. Altered source versions must be plainly marked as such, and must not be */
/* misrepresented as being the original software. */
/* */
/* 3. This notice may not be removed or altered from any source distribution. */
/* */
/******************************************************************************/
/* */
/* Date/Time module providing functionality for both UTC and Local values. */
/* Uses a standard Epoch of 1/1/1970 00:00:00 */
/* */
/* Provides full support if WIN32 is defined, otherwise defaults to GMT */
/* */
/******************************************************************************/
#include "dl_time.h"
/******************************************************************************/
//
// CONSTANTS
//
#define kMIN_YEAR 1970
#define kMAX_YEAR 2106
#define kTIMESTAMP_MIN_VALUE "19700101000000"
#define kTIMESTAMP_MAX_VALUE "21060207062815"
#define kSECONDS_IN_MINUTE 60
#define kMINUTES_IN_HOUR 60
#define kHOURS_IN_DAY 24
#define kDAYS_IN_NORMAL_YEAR 365
#define kSECONDS_IN_HOUR (kMINUTES_IN_HOUR * kSECONDS_IN_MINUTE)
#define kSECONDS_IN_DAY (kHOURS_IN_DAY * kSECONDS_IN_HOUR)
#define kSECONDS_IN_NORMAL_YEAR (kDAYS_IN_NORMAL_YEAR * kSECONDS_IN_DAY)
#define kSECONDS_IN_LEAP_YEAR (kSECONDS_IN_NORMAL_YEAR + kSECONDS_IN_DAY)
// indicates the day of week for 1/1/1970 (eg Thursday)
#define kFIRST_DAY_1970 kDL_TIME_DOW_THURSDAY
/******************************************************************************/
//
// TYPES
//
struct TZ_INFO_S
{
/* seconds to be added to UTC to get 'base' localtime */
DL_SINT32 baseBias;
/* indicates if DST is used */
int hasDST; /* 0:No, else Yes */
/* DST */
DL_SINT32 dstBias;
DL_TIME dstStart;
DL_TIME dstEnd;
};
typedef struct TZ_INFO_S TZ_INFO;
/******************************************************************************/
//
// MACROS
//
/* indicates whether the specified year is a leap year */
#define isLeapYear(year)\
((year%4)?0:((year%100)?1:((year%400)?0:1)))
#define TZ_INFO_BASE_BIAS(tzInfo) ((tzInfo)->baseBias)
#define TZ_INFO_HAS_DST(tzInfo) ((tzInfo)->hasDST)
#define TZ_INFO_DST_BIAS(tzInfo) ((tzInfo)->dstBias)
/******************************************************************************/
//
// PRIVATE VARIABLES
//
static int _haveTZ = 0;
static TZ_INFO _tz;
/******************************************************************************/
// NB only loads time-zone details on the first execution
static void _get_tz_info ( void );
/******************************************************************************/
static void DL_TIME_Populate ( int iYear,
int iMonth,
int iDay,
int iHour,
int iMinute,
int iSecond,
int _iDayOfWeek,
DL_TIME *oData );
/******************************************************************************/
static void seconds_to_struct ( DL_UINT32 iSeconds,
DL_TIME *oData );
/******************************************************************************/
/* NB '_year' should be specified if 'day-in-month' mode used */
static void struct_to_timestamp ( int _iYear,
const DL_TIME *iData,
char *oTimestampStr );
/******************************************************************************/
/* NB '_year' should be specified if 'day-in-month' mode used */
static void struct_to_seconds ( int _iYear,
const DL_TIME *iData,
DL_UINT32 *oSeconds );
/* converts a timestamp (YYYYMMDDHHMISS) to the date/time structure */
/* returns: 1 if ok / 0 otherwise (eg invalid timestamp) */
static int timestamp_to_struct ( const char *iTimestampStr,
DL_TIME *oData );
/******************************************************************************/
// ensures that any 'Day-in-Month' values are converted to absolute
static void rationalise_struct ( int _iYear,
const DL_TIME *iData,
DL_TIME *oData );
static int calc_day_of_week ( int iYear,
int iMonth,
int iDay );
static int calc_days_in_month ( int iYear,
int iMonth );
static void calc_dst_start_end ( int _iYear,
DL_UINT32 *iDstStart,
DL_UINT32 *iDstEnd );
/******************************************************************************/
DL_UINT32 DL_TIME_GetUTCSeconds ( void )
{
DL_UINT32 ret = 0;
ret = (DL_UINT32)(time(NULL) & DL_MAX_UINT32);
return ret;
}
/******************************************************************************/
void DL_TIME_ConvUTCSecondsToLocalStruct ( DL_UINT32 iUtcSecs,
DL_TIME *oData )
{
/* get time-zone specific settings */
_get_tz_info();
/* apply base Bias to UTC value */
iUtcSecs += TZ_INFO_BASE_BIAS(&_tz);
/* convert seconds to struct */
seconds_to_struct(iUtcSecs,oData);
/* perform Std/DST adjustment (where required) */
if ( TZ_INFO_HAS_DST(&_tz) )
{
int inDST = 0;
DL_UINT32 dstStart = 0,
dstEnd = 0;
calc_dst_start_end(oData->year,&dstStart,&dstEnd);
if ( ((dstStart <= dstEnd) && (iUtcSecs >= dstStart) && (iUtcSecs < dstEnd)) ||
((dstStart > dstEnd) && ((iUtcSecs >= dstStart) || (iUtcSecs < dstEnd))) )
{
inDST = 1;
}
if ( inDST )
{
/* apply DST bias */
iUtcSecs += TZ_INFO_DST_BIAS(&_tz);
}
/* convert seconds to struct */
seconds_to_struct(iUtcSecs,oData);
}
return;
}
/******************************************************************************/
void DL_TIME_ConvUTCSecondsToLocalTimestamp ( DL_UINT32 iUtcSecs,
char oTimestamp[] )
{
DL_TIME st;
/* convert seconds (utc) to struct (local) */
DL_TIME_ConvUTCSecondsToLocalStruct(iUtcSecs,&st);
/* convert struct to timestamp */
struct_to_timestamp(0,&st,oTimestamp);
return;
}
/******************************************************************************/
void DL_TIME_ConvUTCSecondsToUTCStruct ( DL_UINT32 iUtcSecs,
DL_TIME *oData )
{
/* convert seconds to struct */
seconds_to_struct(iUtcSecs,oData);
return;
}
/******************************************************************************/
void DL_TIME_ConvUTCSecondsToUTCTimestamp ( DL_UINT32 iUtcSecs,
char oTimestamp[] )
{
DL_TIME st;
/* convert seconds (utc) to struct (utc) */
DL_TIME_ConvUTCSecondsToUTCStruct(iUtcSecs,&st);
/* convert struct to timestamp */
struct_to_timestamp(0,&st,oTimestamp);
return;
}
/******************************************************************************/
int DL_TIME_ConvUTCTimestampToUTCSeconds ( const char iTimestamp[],
DL_UINT32 *oUtcSecs )
{
int ok = 1;
DL_TIME st;
/* init outputs */
*oUtcSecs = 0;
/* timestamp (utc) to struct (utc) */
ok = timestamp_to_struct(iTimestamp,&st);
if ( ok )
{
/* struct (utc) to seconds (utc) */
struct_to_seconds(0,&st,oUtcSecs);
}
return ok;
}
/******************************************************************************/
int DL_TIME_ConvLocalTimestampToUTCSeconds ( const char iTimestamp[],
DL_UINT32 *oUtcSecs )
{
int ok = 1;
DL_TIME st;
/* init outputs */
*oUtcSecs = 0;
/* get time-zone specific settings */
_get_tz_info();
/* timestamp (local) to struct (local) */
ok = timestamp_to_struct(iTimestamp,&st);
if ( ok )
{
/* struct (local) to seconds (local) */
struct_to_seconds(0,&st,oUtcSecs);
/* perform Std/DST adjustment (where required) */
if ( TZ_INFO_HAS_DST(&_tz) )
{
int inDST = 0;
DL_UINT32 dstStart = 0,
dstEnd = 0;
calc_dst_start_end(st.year,&dstStart,&dstEnd);
dstStart += TZ_INFO_DST_BIAS(&_tz);
dstEnd -= TZ_INFO_DST_BIAS(&_tz);
if ( ((dstStart <= dstEnd) && (*oUtcSecs >= dstStart) && (*oUtcSecs < dstEnd)) ||
((dstStart > dstEnd) && ((*oUtcSecs >= dstStart) || (*oUtcSecs < dstEnd))) )
{
inDST = 1;
}
if ( inDST )
{
/* remove DST bias */
*oUtcSecs -= TZ_INFO_DST_BIAS(&_tz);
}
}
/* remove base Bias to UTC value */
*oUtcSecs -= TZ_INFO_BASE_BIAS(&_tz);
}
return ok;
}
/******************************************************************************/
void DL_TIME_ConvUTCSecondsToLocalFormatStr ( DL_UINT32 iUtcSecs,
char *ioFormatStr )
{
DL_TIME st;
/* init outputs */
sprintf(ioFormatStr,"");
/* convert UTC seconds to Local structure */
DL_TIME_ConvUTCSecondsToLocalStruct(iUtcSecs,&st);
/* populate buffer */
sprintf(ioFormatStr,"%02d/%02d/%04d (%02d:%02d:%02d)",
st.day,
st.month,
st.year,
st.hour,
st.minute,
st.second);
return;
}
/******************************************************************************/
int _DL_TIME_AddMonths ( DL_UINT32 iSeconds,
DL_UINT16 iNumMonths,
DL_UINT32 *oSeconds )
{
int ok = 1;
DL_TIME dt;
/* convert to nice date/time format */
DL_TIME_ConvUTCSecondsToUTCStruct(iSeconds,&dt);
if ( ok )
{
int years = iNumMonths / 12;
int months = iNumMonths % 12;
/* add whole years */
dt.year += years;
/* add partial months (may cause year overflow) */
if ( (dt.month + months) <= 12 ) /* same year */
{
dt.month += months;
}
else /* next year */
{
dt.year++;
dt.month = (dt.month + months) - 12;
}
/* adjust 'day' if exceeds maximum for month/year combination */
dt.day = MAX(dt.day,calc_days_in_month(dt.year,dt.month));
}
/* convert back to seconds and pass to caller */
if ( ok )
{
/* struct (utc) to seconds (utc) */
struct_to_seconds(0,&dt,oSeconds);
}
/* check for seconds overflow */
if ( ok && (iSeconds > *oSeconds) )
{
/* overflow because input is greater than output */
ok = 0;
}
return ok;
}
/******************************************************************************/
void _DL_TIME_GetDaysInMonth ( int iMonth,
int iYear,
int *oDaysInMonth )
{
/* init outputs */
*oDaysInMonth = 0;
/* determine 'days in month' */
*oDaysInMonth = calc_days_in_month(iYear,iMonth);
return;
}
/******************************************************************************/
static void _get_tz_info ( void )
{
/* do nothing if we have already loaded the time zone details */
if ( _haveTZ )
return;
/* init structure */
DL_MEM_memset(&_tz,0,sizeof(TZ_INFO));
#if defined(DL_WIN32)
{
TIME_ZONE_INFORMATION winTZ;
DWORD rc;
int tempOk = 1;
/* get timezone */
rc = GetTimeZoneInformation(&winTZ);
if ( rc == TIME_ZONE_ID_UNKNOWN )
{
/* timezone does NOT have DST */
_tz.hasDST = 0;
}
else if ( (rc == TIME_ZONE_ID_STANDARD) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -