mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +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;
 | 
						|
}
 |