1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
/**********************************************************************
* $Id: cpl_time.cpp 33783 2016-03-24 13:45:22Z goatbar $
*
* Name: cpl_time.cpp
* Project: CPL - Common Portability Library
* Purpose: Time functions.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
**********************************************************************
*
* CPLUnixTimeToYMDHMS() is derived from timesub() in localtime.c from
* openbsd/freebsd/netbsd.
*
* CPLYMDHMSToUnixTime() has been implemented by Even Rouault and is in the
* public domain.
*
* c.f. http://svn.freebsd.org/viewvc/base/stable/7/lib/libc/stdtime/localtime.c?revision=178142&view=markup
* localtime.c comes with the following header :
*
* This file is in the public domain, so clarified as of
* 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
*/
#include "cpl_time.h"
#include "cpl_error.h"
static const int SECSPERMIN = 60;
static const int MINSPERHOUR = 60;
static const int HOURSPERDAY = 24;
static const int SECSPERHOUR = SECSPERMIN * MINSPERHOUR;
static const int SECSPERDAY = SECSPERHOUR * HOURSPERDAY;
static const int DAYSPERWEEK = 7;
static const int MONSPERYEAR = 12;
static const int EPOCH_YEAR = 1970;
static const int EPOCH_WDAY = 4;
static const int TM_YEAR_BASE = 1900;
static const int DAYSPERNYEAR = 365;
static const int DAYSPERLYEAR = 366;
static bool isleap(int y) {
return ((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0;
}
static int LEAPS_THROUGH_END_OF(int y) {
return y / 4 - y / 100 + y / 400;
}
static const int mon_lengths[2][MONSPERYEAR] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
} ;
static const int year_lengths[2] = { DAYSPERNYEAR, DAYSPERLYEAR };
/************************************************************************/
/* CPLUnixTimeToYMDHMS() */
/************************************************************************/
/** Converts a time value since the Epoch (aka "unix" time) to a broken-down
* UTC time.
*
* This function is similar to gmtime_r().
* This function will always set tm_isdst to 0.
*
* @param unixTime number of seconds since the Epoch.
* @param pRet address of the return structure.
*
* @return the structure pointed by pRet filled with a broken-down UTC time.
*/
struct tm * CPLUnixTimeToYMDHMS(GIntBig unixTime, struct tm* pRet)
{
GIntBig days = unixTime / SECSPERDAY;
GIntBig rem = unixTime % SECSPERDAY;
if( unixTime < -(GIntBig)10000 * SECSPERDAY * DAYSPERLYEAR ||
unixTime > (GIntBig)10000 * SECSPERDAY * DAYSPERLYEAR )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Invalid unixTime = " CPL_FRMT_GIB,
unixTime);
memset(pRet, 0, sizeof(*pRet));
return pRet;
}
while (rem < 0) {
rem += SECSPERDAY;
--days;
}
pRet->tm_hour = static_cast<int>( rem / SECSPERHOUR );
rem = rem % SECSPERHOUR;
pRet->tm_min = static_cast<int>( rem / SECSPERMIN );
/*
** A positive leap second requires a special
** representation. This uses "... ??:59:60" et seq.
*/
pRet->tm_sec = static_cast<int>( rem % SECSPERMIN );
pRet->tm_wday = static_cast<int>( (EPOCH_WDAY + days) % DAYSPERWEEK );
if (pRet->tm_wday < 0)
pRet->tm_wday += DAYSPERWEEK;
int y = EPOCH_YEAR;
int yleap = 0;
while ( days < 0
|| days >= static_cast<GIntBig>( year_lengths[yleap = isleap(y)] ) )
{
int newy = y + static_cast<int>( days / DAYSPERNYEAR );
if (days < 0)
--newy;
days -= (newy - y) * DAYSPERNYEAR +
LEAPS_THROUGH_END_OF(newy - 1) -
LEAPS_THROUGH_END_OF(y - 1);
y = newy;
}
pRet->tm_year = static_cast<int>( y - TM_YEAR_BASE );
pRet->tm_yday = static_cast<int>( days );
const int* ip = mon_lengths[yleap];
for (pRet->tm_mon = 0;
days >= static_cast<GIntBig>( ip[pRet->tm_mon] );
++(pRet->tm_mon) )
days = days - static_cast<GIntBig>( ip[pRet->tm_mon] );
pRet->tm_mday = static_cast<int>( (days + 1) );
pRet->tm_isdst = 0;
return pRet;
}
/************************************************************************/
/* CPLYMDHMSToUnixTime() */
/************************************************************************/
/** Converts a broken-down UTC time into time since the Epoch (aka "unix" time).
*
* This function is similar to mktime(), but the passed structure is not
* modified. This function ignores the tm_wday, tm_yday and tm_isdst fields of
* the passed value. No timezone shift will be applied. This function
* returns 0 for the 1/1/1970 00:00:00
*
* @param brokendowntime broken-downtime UTC time.
*
* @return a number of seconds since the Epoch encoded as a value of type
* GIntBig, or -1 if the time cannot be represented.
*/
GIntBig CPLYMDHMSToUnixTime(const struct tm *brokendowntime)
{
if (brokendowntime->tm_mon < 0 || brokendowntime->tm_mon >= 12)
return -1;
/* Number of days of the current month */
GIntBig days = brokendowntime->tm_mday - 1;
/* Add the number of days of the current year */
const int* ip = mon_lengths[static_cast<int>(isleap(TM_YEAR_BASE + brokendowntime->tm_year))];
for( int mon = 0; mon < brokendowntime->tm_mon; mon++ )
days += ip[mon];
/* Add the number of days of the other years */
days +=
( TM_YEAR_BASE
+ static_cast<GIntBig>( brokendowntime->tm_year )
- EPOCH_YEAR ) * DAYSPERNYEAR
+ LEAPS_THROUGH_END_OF( static_cast<int> (TM_YEAR_BASE )
+ static_cast<int>( brokendowntime->tm_year )
- static_cast<int>( 1 ) )
- LEAPS_THROUGH_END_OF( EPOCH_YEAR - 1 );
/* Now add the secondes, minutes and hours to the number of days since EPOCH */
return brokendowntime->tm_sec +
brokendowntime->tm_min * SECSPERMIN +
brokendowntime->tm_hour * SECSPERHOUR +
days * SECSPERDAY;
}
|