mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			245 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* -*- c-basic-offset: 2 -*- */
 | |
| /*
 | |
|   Copyright(C) 2009-2016 Brazil
 | |
| 
 | |
|   This library is free software; you can redistribute it and/or
 | |
|   modify it under the terms of the GNU Lesser General Public
 | |
|   License version 2.1 as published by the Free Software Foundation.
 | |
| 
 | |
|   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 GNU
 | |
|   Lesser General Public License for more details.
 | |
| 
 | |
|   You should have received a copy of the GNU Lesser General Public
 | |
|   License along with this library; if not, write to the Free Software
 | |
|   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
 | |
| */
 | |
| 
 | |
| #include "grn_time.h"
 | |
| #include "grn_ctx.h"
 | |
| #include "grn_str.h"
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #if defined(HAVE__LOCALTIME64_S) && defined(__GNUC__)
 | |
| # ifdef _WIN64
 | |
| #  define localtime_s(tm, time) _localtime64_s(tm, time)
 | |
| # else /* _WIN64 */
 | |
| #  define localtime_s(tm, time) _localtime32_s(tm, time)
 | |
| # endif /* _WIN64 */
 | |
| #endif /* defined(HAVE__LOCALTIME64_S) && defined(__GNUC__) */
 | |
| 
 | |
| /* fixme by 2038 */
 | |
| 
 | |
| grn_rc
 | |
| grn_timeval_now(grn_ctx *ctx, grn_timeval *tv)
 | |
| {
 | |
| #ifdef HAVE_CLOCK_GETTIME
 | |
|   struct timespec t;
 | |
|   if (clock_gettime(CLOCK_REALTIME, &t)) {
 | |
|     SERR("clock_gettime");
 | |
|   } else {
 | |
|     tv->tv_sec = t.tv_sec;
 | |
|     tv->tv_nsec = t.tv_nsec;
 | |
|   }
 | |
|   return ctx->rc;
 | |
| #else /* HAVE_CLOCK_GETTIME */
 | |
| # ifdef WIN32
 | |
|   time_t t;
 | |
|   struct _timeb tb;
 | |
|   time(&t);
 | |
|   _ftime(&tb);
 | |
|   tv->tv_sec = t;
 | |
|   tv->tv_nsec = tb.millitm * (GRN_TIME_NSEC_PER_SEC / 1000);
 | |
|   return GRN_SUCCESS;
 | |
| # else /* WIN32 */
 | |
|   struct timeval t;
 | |
|   if (gettimeofday(&t, NULL)) {
 | |
|     SERR("gettimeofday");
 | |
|   } else {
 | |
|     tv->tv_sec = t.tv_sec;
 | |
|     tv->tv_nsec = GRN_TIME_USEC_TO_NSEC(t.tv_usec);
 | |
|   }
 | |
|   return ctx->rc;
 | |
| # endif /* WIN32 */
 | |
| #endif /* HAVE_CLOCK_GETTIME */
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_time_now(grn_ctx *ctx, grn_obj *obj)
 | |
| {
 | |
|   grn_timeval tv;
 | |
|   grn_timeval_now(ctx, &tv);
 | |
|   GRN_TIME_SET(ctx, obj, GRN_TIME_PACK(tv.tv_sec,
 | |
|                                        GRN_TIME_NSEC_TO_USEC(tv.tv_nsec)));
 | |
| }
 | |
| 
 | |
| static grn_bool
 | |
| grn_time_t_to_tm(grn_ctx *ctx, const time_t time, struct tm *tm)
 | |
| {
 | |
|   grn_bool success;
 | |
|   const char *function_name;
 | |
| #ifdef HAVE__LOCALTIME64_S
 | |
|   function_name = "localtime_s";
 | |
|   success = (localtime_s(tm, &time) == 0);
 | |
| #else /* HAVE__LOCALTIME64_S */
 | |
| # ifdef HAVE_LOCALTIME_R
 | |
|   function_name = "localtime_r";
 | |
|   success = (localtime_r(&time, tm) != NULL);
 | |
| # else /* HAVE_LOCALTIME_R */
 | |
|   function_name = "localtime";
 | |
|   {
 | |
|     struct tm *local_tm;
 | |
|     local_tm = localtime(&time);
 | |
|     if (local_tm) {
 | |
|       success = GRN_TRUE;
 | |
|       memcpy(tm, local_tm, sizeof(struct tm));
 | |
|     } else {
 | |
|       success = GRN_FALSE;
 | |
|     }
 | |
|   }
 | |
| # endif /* HAVE_LOCALTIME_R */
 | |
| #endif /* HAVE__LOCALTIME64_S */
 | |
|   if (!success) {
 | |
|     SERR("%s: failed to convert time_t to struct tm: <%" GRN_FMT_INT64D ">",
 | |
|          function_name,
 | |
|          (int64_t)time);
 | |
|   }
 | |
|   return success;
 | |
| }
 | |
| 
 | |
| struct tm *
 | |
| grn_timeval2tm(grn_ctx *ctx, grn_timeval *tv, struct tm *tm)
 | |
| {
 | |
|   if (grn_time_t_to_tm(ctx, tv->tv_sec, tm)) {
 | |
|     return tm;
 | |
|   } else {
 | |
|     return NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| grn_bool
 | |
| grn_time_to_tm(grn_ctx *ctx, int64_t time, struct tm *tm)
 | |
| {
 | |
|   int64_t sec;
 | |
|   int32_t usec;
 | |
| 
 | |
|   GRN_TIME_UNPACK(time, sec, usec);
 | |
|   return grn_time_t_to_tm(ctx, sec, tm);
 | |
| }
 | |
| 
 | |
| static grn_bool
 | |
| grn_time_t_from_tm(grn_ctx *ctx, time_t *time, struct tm *tm)
 | |
| {
 | |
|   grn_bool success;
 | |
| 
 | |
|   tm->tm_yday = -1;
 | |
|   *time = mktime(tm);
 | |
|   success = (tm->tm_yday != -1);
 | |
|   if (!success) {
 | |
|     ERR(GRN_INVALID_ARGUMENT,
 | |
|         "mktime: failed to convert struct tm to time_t: "
 | |
|         "<%04d-%02d-%02dT%02d:%02d:%02d>(%d)",
 | |
|         1900 + tm->tm_year,
 | |
|         tm->tm_mon + 1,
 | |
|         tm->tm_mday,
 | |
|         tm->tm_hour,
 | |
|         tm->tm_min,
 | |
|         tm->tm_sec,
 | |
|         tm->tm_isdst);
 | |
|   }
 | |
|   return success;
 | |
| }
 | |
| 
 | |
| grn_bool
 | |
| grn_time_from_tm(grn_ctx *ctx, int64_t *time, struct tm *tm)
 | |
| {
 | |
|   time_t sec_time_t;
 | |
|   int64_t sec;
 | |
|   int32_t usec = 0;
 | |
| 
 | |
|   if (!grn_time_t_from_tm(ctx, &sec_time_t, tm)) {
 | |
|     return GRN_FALSE;
 | |
|   }
 | |
| 
 | |
|   sec = sec_time_t;
 | |
|   *time = GRN_TIME_PACK(sec, usec);
 | |
|   return GRN_TRUE;
 | |
| }
 | |
| 
 | |
| grn_rc
 | |
| grn_timeval2str(grn_ctx *ctx, grn_timeval *tv, char *buf, size_t buf_size)
 | |
| {
 | |
|   struct tm tm;
 | |
|   struct tm *ltm;
 | |
|   ltm = grn_timeval2tm(ctx, tv, &tm);
 | |
|   grn_snprintf(buf, buf_size, GRN_TIMEVAL_STR_SIZE,
 | |
|                GRN_TIMEVAL_STR_FORMAT,
 | |
|                ltm->tm_year + 1900, ltm->tm_mon + 1, ltm->tm_mday,
 | |
|                ltm->tm_hour, ltm->tm_min, ltm->tm_sec,
 | |
|                (int)(GRN_TIME_NSEC_TO_USEC(tv->tv_nsec)));
 | |
|   if (buf_size > GRN_TIMEVAL_STR_SIZE) {
 | |
|     buf[GRN_TIMEVAL_STR_SIZE - 1] = '\0';
 | |
|   } else {
 | |
|     buf[buf_size - 1] = '\0';
 | |
|   }
 | |
|   return ctx->rc;
 | |
| }
 | |
| 
 | |
| grn_rc
 | |
| grn_str2timeval(const char *str, uint32_t str_len, grn_timeval *tv)
 | |
| {
 | |
|   struct tm tm;
 | |
|   const char *r1, *r2, *rend = str + str_len;
 | |
|   uint32_t uv;
 | |
|   memset(&tm, 0, sizeof(struct tm));
 | |
| 
 | |
|   tm.tm_year = (int)grn_atoui(str, rend, &r1) - 1900;
 | |
|   if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-')) {
 | |
|     return GRN_INVALID_ARGUMENT;
 | |
|   }
 | |
|   r1++;
 | |
|   tm.tm_mon = (int)grn_atoui(r1, rend, &r1) - 1;
 | |
|   if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-') ||
 | |
|       tm.tm_mon < 0 || tm.tm_mon >= 12) { return GRN_INVALID_ARGUMENT; }
 | |
|   r1++;
 | |
|   tm.tm_mday = (int)grn_atoui(r1, rend, &r1);
 | |
|   if ((r1 + 1) >= rend || *r1 != ' ' ||
 | |
|       tm.tm_mday < 1 || tm.tm_mday > 31) { return GRN_INVALID_ARGUMENT; }
 | |
| 
 | |
|   tm.tm_hour = (int)grn_atoui(++r1, rend, &r2);
 | |
|   if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
 | |
|       tm.tm_hour < 0 || tm.tm_hour >= 24) {
 | |
|     return GRN_INVALID_ARGUMENT;
 | |
|   }
 | |
|   r1 = r2 + 1;
 | |
|   tm.tm_min = (int)grn_atoui(r1, rend, &r2);
 | |
|   if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
 | |
|       tm.tm_min < 0 || tm.tm_min >= 60) {
 | |
|     return GRN_INVALID_ARGUMENT;
 | |
|   }
 | |
|   r1 = r2 + 1;
 | |
|   tm.tm_sec = (int)grn_atoui(r1, rend, &r2);
 | |
|   if (r1 == r2 ||
 | |
|       tm.tm_sec < 0 || tm.tm_sec > 61 /* leap 2sec */) {
 | |
|     return GRN_INVALID_ARGUMENT;
 | |
|   }
 | |
|   r1 = r2;
 | |
|   tm.tm_yday = -1;
 | |
|   tm.tm_isdst = -1;
 | |
| 
 | |
|   /* tm_yday is set appropriately (0-365) on successful completion. */
 | |
|   tv->tv_sec = mktime(&tm);
 | |
|   if (tm.tm_yday == -1) { return GRN_INVALID_ARGUMENT; }
 | |
|   if ((r1 + 1) < rend && *r1 == '.') { r1++; }
 | |
|   uv = grn_atoi(r1, rend, &r2);
 | |
|   while (r2 < r1 + 6) {
 | |
|     uv *= 10;
 | |
|     r2++;
 | |
|   }
 | |
|   if (uv >= GRN_TIME_USEC_PER_SEC) { return GRN_INVALID_ARGUMENT; }
 | |
|   tv->tv_nsec = GRN_TIME_USEC_TO_NSEC(uv);
 | |
|   return GRN_SUCCESS;
 | |
| }
 | 
