You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
4.4 KiB
162 lines
4.4 KiB
/* -*- coding: utf-8 -*-
|
|
* ----------------------------------------------------------------------
|
|
* Copyright © 2011-2013, RedJack, LLC.
|
|
* All rights reserved.
|
|
*
|
|
* Please see the COPYING file in this distribution for license details.
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "libcork/core/timestamp.h"
|
|
#include "libcork/core/types.h"
|
|
#include "libcork/helpers/errors.h"
|
|
|
|
void
|
|
cork_timestamp_init_now(cork_timestamp *ts)
|
|
{
|
|
struct timeval tp;
|
|
gettimeofday(&tp, NULL);
|
|
cork_timestamp_init_usec(ts, tp.tv_sec, tp.tv_usec);
|
|
}
|
|
|
|
|
|
#define is_digit(ch) ((ch) >= '0' && (ch) <= '9')
|
|
|
|
static uint64_t
|
|
power_of_10(unsigned int width)
|
|
{
|
|
uint64_t accumulator = 10;
|
|
uint64_t result = 1;
|
|
while (width != 0) {
|
|
if ((width % 2) == 1) {
|
|
result *= accumulator;
|
|
width--;
|
|
}
|
|
accumulator *= accumulator;
|
|
width /= 2;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int
|
|
append_fractional(const cork_timestamp ts, unsigned int width,
|
|
struct cork_buffer *dest)
|
|
{
|
|
if (CORK_UNLIKELY(width == 0 || width > 9)) {
|
|
cork_error_set_printf
|
|
(EINVAL,
|
|
"Invalid width %u for fractional cork_timestamp", width);
|
|
return -1;
|
|
} else {
|
|
uint64_t denom = power_of_10(width);
|
|
uint64_t frac = cork_timestamp_gsec_to_units(ts, denom);
|
|
cork_buffer_append_printf(dest, "%0*" PRIu64, width, frac);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
cork_timestamp_format_parts(const cork_timestamp ts, struct tm *tm,
|
|
const char *format, struct cork_buffer *dest)
|
|
{
|
|
const char *next_percent;
|
|
|
|
while ((next_percent = strchr(format, '%')) != NULL) {
|
|
const char *spec = next_percent + 1;
|
|
unsigned int width = 0;
|
|
|
|
/* First append any text in between the previous format specifier and
|
|
* this one. */
|
|
cork_buffer_append(dest, format, next_percent - format);
|
|
|
|
/* Then parse the format specifier */
|
|
while (is_digit(*spec)) {
|
|
width *= 10;
|
|
width += (*spec++ - '0');
|
|
}
|
|
|
|
switch (*spec) {
|
|
case '\0':
|
|
cork_error_set_string
|
|
(EINVAL,
|
|
"Trailing %% at end of cork_timestamp format string");
|
|
return -1;
|
|
|
|
case '%':
|
|
cork_buffer_append(dest, "%", 1);
|
|
break;
|
|
|
|
case 'Y':
|
|
cork_buffer_append_printf(dest, "%04d", tm->tm_year + 1900);
|
|
break;
|
|
|
|
case 'm':
|
|
cork_buffer_append_printf(dest, "%02d", tm->tm_mon + 1);
|
|
break;
|
|
|
|
case 'd':
|
|
cork_buffer_append_printf(dest, "%02d", tm->tm_mday);
|
|
break;
|
|
|
|
case 'H':
|
|
cork_buffer_append_printf(dest, "%02d", tm->tm_hour);
|
|
break;
|
|
|
|
case 'M':
|
|
cork_buffer_append_printf(dest, "%02d", tm->tm_min);
|
|
break;
|
|
|
|
case 'S':
|
|
cork_buffer_append_printf(dest, "%02d", tm->tm_sec);
|
|
break;
|
|
|
|
case 's':
|
|
cork_buffer_append_printf
|
|
(dest, "%" PRIu32, cork_timestamp_sec(ts));
|
|
break;
|
|
|
|
case 'f':
|
|
rii_check(append_fractional(ts, width, dest));
|
|
break;
|
|
|
|
default:
|
|
cork_error_set_printf
|
|
(EINVAL,
|
|
"Unknown cork_timestamp format specifier %%%c", *spec);
|
|
return -1;
|
|
}
|
|
|
|
format = spec + 1;
|
|
}
|
|
|
|
/* When we fall through, there is some additional content after the final
|
|
* format specifier. */
|
|
cork_buffer_append_string(dest, format);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cork_timestamp_format_utc(const cork_timestamp ts, const char *format,
|
|
struct cork_buffer *dest)
|
|
{
|
|
time_t clock;
|
|
struct tm tm;
|
|
clock = cork_timestamp_sec(ts);
|
|
gmtime_r(&clock, &tm);
|
|
return cork_timestamp_format_parts(ts, &tm, format, dest);
|
|
}
|
|
|
|
int
|
|
cork_timestamp_format_local(const cork_timestamp ts, const char *format,
|
|
struct cork_buffer *dest)
|
|
{
|
|
time_t clock;
|
|
struct tm tm;
|
|
clock = cork_timestamp_sec(ts);
|
|
localtime_r(&clock, &tm);
|
|
return cork_timestamp_format_parts(ts, &tm, format, dest);
|
|
}
|