Merge pull request #3199 from Carbenium/localtime
Use thread-safe localtime and gmtime versions
This commit is contained in:
commit
da0fa3e08a
|
@ -71,8 +71,8 @@ Event::Event(
|
||||||
std::string notes;
|
std::string notes;
|
||||||
createNotes(notes);
|
createNotes(notes);
|
||||||
|
|
||||||
struct timeval now;
|
timeval now = {};
|
||||||
gettimeofday(&now, 0);
|
gettimeofday(&now, nullptr);
|
||||||
|
|
||||||
if ( !start_time.tv_sec ) {
|
if ( !start_time.tv_sec ) {
|
||||||
Warning("Event has zero time, setting to now");
|
Warning("Event has zero time, setting to now");
|
||||||
|
@ -80,12 +80,12 @@ Event::Event(
|
||||||
} else if ( start_time.tv_sec > now.tv_sec ) {
|
} else if ( start_time.tv_sec > now.tv_sec ) {
|
||||||
char buffer[26];
|
char buffer[26];
|
||||||
char buffer_now[26];
|
char buffer_now[26];
|
||||||
struct tm* tm_info;
|
tm tm_info = {};
|
||||||
|
|
||||||
tm_info = localtime(&start_time.tv_sec);
|
localtime_r(&start_time.tv_sec, &tm_info);
|
||||||
strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", tm_info);
|
strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", &tm_info);
|
||||||
tm_info = localtime(&now.tv_sec);
|
localtime_r(&now.tv_sec, &tm_info);
|
||||||
strftime(buffer_now, 26, "%Y:%m:%d %H:%M:%S", tm_info);
|
strftime(buffer_now, 26, "%Y:%m:%d %H:%M:%S", &tm_info);
|
||||||
|
|
||||||
Error(
|
Error(
|
||||||
"StartDateTime in the future starttime %u.%u >? now %u.%u difference %d\n%s\n%s",
|
"StartDateTime in the future starttime %u.%u >? now %u.%u difference %d\n%s\n%s",
|
||||||
|
@ -661,16 +661,17 @@ bool Event::SetPath(Storage *storage) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tm *stime = localtime(&start_time.tv_sec);
|
tm stime = {};
|
||||||
|
localtime_r(&start_time.tv_sec, &stime);
|
||||||
if ( scheme == Storage::DEEP ) {
|
if ( scheme == Storage::DEEP ) {
|
||||||
|
|
||||||
int dt_parts[6];
|
int dt_parts[6];
|
||||||
dt_parts[0] = stime->tm_year-100;
|
dt_parts[0] = stime.tm_year-100;
|
||||||
dt_parts[1] = stime->tm_mon+1;
|
dt_parts[1] = stime.tm_mon+1;
|
||||||
dt_parts[2] = stime->tm_mday;
|
dt_parts[2] = stime.tm_mday;
|
||||||
dt_parts[3] = stime->tm_hour;
|
dt_parts[3] = stime.tm_hour;
|
||||||
dt_parts[4] = stime->tm_min;
|
dt_parts[4] = stime.tm_min;
|
||||||
dt_parts[5] = stime->tm_sec;
|
dt_parts[5] = stime.tm_sec;
|
||||||
|
|
||||||
std::string date_path;
|
std::string date_path;
|
||||||
std::string time_path;
|
std::string time_path;
|
||||||
|
@ -685,7 +686,7 @@ bool Event::SetPath(Storage *storage) {
|
||||||
if ( i == 2 )
|
if ( i == 2 )
|
||||||
date_path = path;
|
date_path = path;
|
||||||
}
|
}
|
||||||
time_path = stringtf("%02d/%02d/%02d", stime->tm_hour, stime->tm_min, stime->tm_sec);
|
time_path = stringtf("%02d/%02d/%02d", stime.tm_hour, stime.tm_min, stime.tm_sec);
|
||||||
|
|
||||||
// Create event id symlink
|
// Create event id symlink
|
||||||
std::string id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id);
|
std::string id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id);
|
||||||
|
@ -695,7 +696,7 @@ bool Event::SetPath(Storage *storage) {
|
||||||
}
|
}
|
||||||
} else if ( scheme == Storage::MEDIUM ) {
|
} else if ( scheme == Storage::MEDIUM ) {
|
||||||
path += stringtf("/%04d-%02d-%02d",
|
path += stringtf("/%04d-%02d-%02d",
|
||||||
stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday
|
stime.tm_year+1900, stime.tm_mon+1, stime.tm_mday
|
||||||
);
|
);
|
||||||
if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) {
|
if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) {
|
||||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||||
|
|
|
@ -138,18 +138,20 @@ class Event {
|
||||||
bool SetPath(Storage *storage);
|
bool SetPath(Storage *storage);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const char *getSubPath(struct tm *time) {
|
static const char *getSubPath(tm time) {
|
||||||
static char subpath[PATH_MAX] = "";
|
static char subpath[PATH_MAX] = "";
|
||||||
snprintf(subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d",
|
snprintf(subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d",
|
||||||
time->tm_year-100, time->tm_mon+1, time->tm_mday,
|
time.tm_year-100, time.tm_mon+1, time.tm_mday,
|
||||||
time->tm_hour, time->tm_min, time->tm_sec);
|
time.tm_hour, time.tm_min, time.tm_sec);
|
||||||
return subpath;
|
return subpath;
|
||||||
}
|
}
|
||||||
static const char *getSubPath(time_t *time) {
|
static const char *getSubPath(time_t *time) {
|
||||||
return Event::getSubPath(localtime(time));
|
tm time_tm = {};
|
||||||
|
localtime_r(time, &time_tm);
|
||||||
|
return Event::getSubPath(time_tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getEventFile(void) const {
|
const char* getEventFile() const {
|
||||||
return video_file.c_str();
|
return video_file.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,33 +171,35 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
const char *storage_path = storage->Path();
|
const char *storage_path = storage->Path();
|
||||||
|
|
||||||
if ( event_data->scheme == Storage::DEEP ) {
|
if ( event_data->scheme == Storage::DEEP ) {
|
||||||
struct tm *event_time = localtime(&event_data->start_time);
|
tm event_time = {};
|
||||||
|
localtime_r(&event_data->start_time, &event_time);
|
||||||
|
|
||||||
if ( storage_path[0] == '/' )
|
if ( storage_path[0] == '/' )
|
||||||
snprintf(event_data->path, sizeof(event_data->path),
|
snprintf(event_data->path, sizeof(event_data->path),
|
||||||
"%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
|
"%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||||
storage_path, event_data->monitor_id,
|
storage_path, event_data->monitor_id,
|
||||||
event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday,
|
event_time.tm_year-100, event_time.tm_mon+1, event_time.tm_mday,
|
||||||
event_time->tm_hour, event_time->tm_min, event_time->tm_sec);
|
event_time.tm_hour, event_time.tm_min, event_time.tm_sec);
|
||||||
else
|
else
|
||||||
snprintf(event_data->path, sizeof(event_data->path),
|
snprintf(event_data->path, sizeof(event_data->path),
|
||||||
"%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
|
"%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||||
event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday,
|
event_time.tm_year-100, event_time.tm_mon+1, event_time.tm_mday,
|
||||||
event_time->tm_hour, event_time->tm_min, event_time->tm_sec);
|
event_time.tm_hour, event_time.tm_min, event_time.tm_sec);
|
||||||
} else if ( event_data->scheme == Storage::MEDIUM ) {
|
} else if ( event_data->scheme == Storage::MEDIUM ) {
|
||||||
struct tm *event_time = localtime(&event_data->start_time);
|
tm event_time = {};
|
||||||
|
localtime_r(&event_data->start_time, &event_time);
|
||||||
if ( storage_path[0] == '/' )
|
if ( storage_path[0] == '/' )
|
||||||
snprintf(event_data->path, sizeof(event_data->path),
|
snprintf(event_data->path, sizeof(event_data->path),
|
||||||
"%s/%u/%04d-%02d-%02d/%" PRIu64,
|
"%s/%u/%04d-%02d-%02d/%" PRIu64,
|
||||||
storage_path, event_data->monitor_id,
|
storage_path, event_data->monitor_id,
|
||||||
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
event_time.tm_year+1900, event_time.tm_mon+1, event_time.tm_mday,
|
||||||
event_data->event_id);
|
event_data->event_id);
|
||||||
else
|
else
|
||||||
snprintf(event_data->path, sizeof(event_data->path),
|
snprintf(event_data->path, sizeof(event_data->path),
|
||||||
"%s/%s/%u/%04d-%02d-%02d/%" PRIu64,
|
"%s/%s/%u/%04d-%02d-%02d/%" PRIu64,
|
||||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||||
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
event_time.tm_year+1900, event_time.tm_mon+1, event_time.tm_mday,
|
||||||
event_data->event_id);
|
event_data->event_id);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1186,7 +1186,8 @@ cinfo->out_color_space = JCS_RGB;
|
||||||
|
|
||||||
// This is a lot of stuff to allocate on the stack. Recommend char *timebuf[64];
|
// This is a lot of stuff to allocate on the stack. Recommend char *timebuf[64];
|
||||||
char timebuf[64], msbuf[64];
|
char timebuf[64], msbuf[64];
|
||||||
strftime(timebuf, sizeof timebuf, "%Y:%m:%d %H:%M:%S", localtime(&(timestamp.tv_sec)));
|
tm timestamp_tm = {};
|
||||||
|
strftime(timebuf, sizeof timebuf, "%Y:%m:%d %H:%M:%S", localtime_r(×tamp.tv_sec, ×tamp_tm));
|
||||||
snprintf(msbuf, sizeof msbuf, "%06d",(int)(timestamp.tv_usec)); // we only use milliseconds because that's all defined in exif, but this is the whole microseconds because we have it
|
snprintf(msbuf, sizeof msbuf, "%06d",(int)(timestamp.tv_usec)); // we only use milliseconds because that's all defined in exif, but this is the whole microseconds because we have it
|
||||||
unsigned char exiftimes[82] = {
|
unsigned char exiftimes[82] = {
|
||||||
0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00,
|
0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
@ -2132,7 +2133,8 @@ void Image::Annotate(
|
||||||
|
|
||||||
void Image::Timestamp( const char *label, const time_t when, const Coord &coord, const int size ) {
|
void Image::Timestamp( const char *label, const time_t when, const Coord &coord, const int size ) {
|
||||||
char time_text[64];
|
char time_text[64];
|
||||||
strftime(time_text, sizeof(time_text), "%y/%m/%d %H:%M:%S", localtime(&when));
|
tm when_tm = {};
|
||||||
|
strftime(time_text, sizeof(time_text), "%y/%m/%d %H:%M:%S", localtime_r(&when, &when_tm));
|
||||||
if ( label ) {
|
if ( label ) {
|
||||||
// Assume label is max 64, + ' - ' + 64 chars of time_text
|
// Assume label is max 64, + ' - ' + 64 chars of time_text
|
||||||
char text[132];
|
char text[132];
|
||||||
|
|
|
@ -447,7 +447,8 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
char *timePtr = timeString;
|
char *timePtr = timeString;
|
||||||
timePtr += strftime(timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec));
|
tm now_tm = {};
|
||||||
|
timePtr += strftime(timePtr, sizeof(timeString), "%x %H:%M:%S", localtime_r(&timeVal.tv_sec, &now_tm));
|
||||||
snprintf(timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec);
|
snprintf(timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec);
|
||||||
#if 0
|
#if 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -2842,7 +2842,8 @@ void Monitor::TimestampImage(Image *ts_image, const struct timeval *ts_time) con
|
||||||
|
|
||||||
// Expand the strftime macros first
|
// Expand the strftime macros first
|
||||||
char label_time_text[256];
|
char label_time_text[256];
|
||||||
strftime(label_time_text, sizeof(label_time_text), label_format, localtime(&ts_time->tv_sec));
|
tm ts_tm = {};
|
||||||
|
strftime(label_time_text, sizeof(label_time_text), label_format, localtime_r(&ts_time->tv_sec, &ts_tm));
|
||||||
char label_text[1024];
|
char label_text[1024];
|
||||||
const char *s_ptr = label_time_text;
|
const char *s_ptr = label_time_text;
|
||||||
char *d_ptr = label_text;
|
char *d_ptr = label_text;
|
||||||
|
|
|
@ -245,18 +245,19 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
||||||
const char *pass = dbrow[2];
|
const char *pass = dbrow[2];
|
||||||
|
|
||||||
time_t our_now = now;
|
time_t our_now = now;
|
||||||
|
tm now_tm = {};
|
||||||
for ( unsigned int i = 0; i < hours; i++, our_now -= 3600 ) {
|
for ( unsigned int i = 0; i < hours; i++, our_now -= 3600 ) {
|
||||||
struct tm *now_tm = localtime(&our_now);
|
localtime_r(&our_now, &now_tm);
|
||||||
|
|
||||||
snprintf(auth_key, sizeof(auth_key)-1, "%s%s%s%s%d%d%d%d",
|
snprintf(auth_key, sizeof(auth_key)-1, "%s%s%s%s%d%d%d%d",
|
||||||
config.auth_hash_secret,
|
config.auth_hash_secret,
|
||||||
user,
|
user,
|
||||||
pass,
|
pass,
|
||||||
remote_addr,
|
remote_addr,
|
||||||
now_tm->tm_hour,
|
now_tm.tm_hour,
|
||||||
now_tm->tm_mday,
|
now_tm.tm_mday,
|
||||||
now_tm->tm_mon,
|
now_tm.tm_mon,
|
||||||
now_tm->tm_year);
|
now_tm.tm_year);
|
||||||
|
|
||||||
#if HAVE_DECL_MD5
|
#if HAVE_DECL_MD5
|
||||||
MD5((unsigned char *)auth_key, strlen(auth_key), md5sum);
|
MD5((unsigned char *)auth_key, strlen(auth_key), md5sum);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "zm_config.h"
|
#include "zm_config.h"
|
||||||
#include "zm_logger.h"
|
#include "zm_logger.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdarg>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fcntl.h> /* Definition of AT_* constants */
|
#include <fcntl.h> /* Definition of AT_* constants */
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -43,7 +43,7 @@ std::string trimSet(std::string str, std::string trimset) {
|
||||||
// Trim Both leading and trailing sets
|
// Trim Both leading and trailing sets
|
||||||
size_t startpos = str.find_first_not_of(trimset); // Find the first character position after excluding leading blank spaces
|
size_t startpos = str.find_first_not_of(trimset); // Find the first character position after excluding leading blank spaces
|
||||||
size_t endpos = str.find_last_not_of(trimset); // Find the first character position from reverse af
|
size_t endpos = str.find_last_not_of(trimset); // Find the first character position from reverse af
|
||||||
|
|
||||||
// if all spaces or empty return an empty string
|
// if all spaces or empty return an empty string
|
||||||
if ( ( std::string::npos == startpos ) || ( std::string::npos == endpos ) )
|
if ( ( std::string::npos == startpos ) || ( std::string::npos == endpos ) )
|
||||||
return std::string("");
|
return std::string("");
|
||||||
|
@ -148,7 +148,7 @@ const std::string base64Encode(const std::string &inString) {
|
||||||
selection = remainder | (*inPtr >> 4);
|
selection = remainder | (*inPtr >> 4);
|
||||||
remainder = (*inPtr++ & 0x0f) << 2;
|
remainder = (*inPtr++ & 0x0f) << 2;
|
||||||
outString += base64_table[selection];
|
outString += base64_table[selection];
|
||||||
|
|
||||||
if ( *inPtr ) {
|
if ( *inPtr ) {
|
||||||
selection = remainder | (*inPtr >> 6);
|
selection = remainder | (*inPtr >> 6);
|
||||||
outString += base64_table[selection];
|
outString += base64_table[selection];
|
||||||
|
@ -175,7 +175,7 @@ int split(const char* string, const char delim, std::vector<std::string>& items)
|
||||||
return -2;
|
return -2;
|
||||||
|
|
||||||
std::string str(string);
|
std::string str(string);
|
||||||
|
|
||||||
while ( true ) {
|
while ( true ) {
|
||||||
size_t pos = str.find(delim);
|
size_t pos = str.find(delim);
|
||||||
items.push_back(str.substr(0, pos));
|
items.push_back(str.substr(0, pos));
|
||||||
|
@ -242,7 +242,7 @@ void hwcaps_detect() {
|
||||||
} else {
|
} else {
|
||||||
sse_version = 0;
|
sse_version = 0;
|
||||||
Debug(1, "Detected a x86\\x86-64 processor");
|
Debug(1, "Detected a x86\\x86-64 processor");
|
||||||
}
|
}
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
// ARM processor in 32bit mode
|
// ARM processor in 32bit mode
|
||||||
// To see if it supports NEON, we need to get that information from the kernel
|
// To see if it supports NEON, we need to get that information from the kernel
|
||||||
|
@ -279,7 +279,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
||||||
"sse2_copy_iter:\n\t"
|
"sse2_copy_iter:\n\t"
|
||||||
"movdqa (%0),%%xmm0\n\t"
|
"movdqa (%0),%%xmm0\n\t"
|
||||||
"movdqa 0x10(%0),%%xmm1\n\t"
|
"movdqa 0x10(%0),%%xmm1\n\t"
|
||||||
"movdqa 0x20(%0),%%xmm2\n\t"
|
"movdqa 0x20(%0),%%xmm2\n\t"
|
||||||
"movdqa 0x30(%0),%%xmm3\n\t"
|
"movdqa 0x30(%0),%%xmm3\n\t"
|
||||||
"movdqa 0x40(%0),%%xmm4\n\t"
|
"movdqa 0x40(%0),%%xmm4\n\t"
|
||||||
"movdqa 0x50(%0),%%xmm5\n\t"
|
"movdqa 0x50(%0),%%xmm5\n\t"
|
||||||
|
@ -328,16 +328,17 @@ void timespec_diff(struct timespec *start, struct timespec *end, struct timespec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *timeval_to_string( struct timeval tv ) {
|
std::string TimevalToString(timeval tv) {
|
||||||
time_t nowtime;
|
tm now = {};
|
||||||
struct tm *nowtm;
|
std::array<char, 26> tm_buf = {};
|
||||||
static char tmbuf[20], buf[28];
|
|
||||||
|
|
||||||
nowtime = tv.tv_sec;
|
localtime_r(&tv.tv_sec, &now);
|
||||||
nowtm = localtime(&nowtime);
|
size_t tm_buf_len = strftime(tm_buf.data(), tm_buf.size(), "%Y-%m-%d %H:%M:%S", &now);
|
||||||
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
|
if (tm_buf_len == 0) {
|
||||||
snprintf(buf, sizeof buf-1, "%s.%06ld", tmbuf, tv.tv_usec);
|
return "";
|
||||||
return buf;
|
}
|
||||||
|
|
||||||
|
return stringtf("%s.%06ld", tm_buf.data(), tv.tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UriDecode( const std::string &encoded ) {
|
std::string UriDecode( const std::string &encoded ) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ void hwcaps_detect();
|
||||||
extern unsigned int sse_version;
|
extern unsigned int sse_version;
|
||||||
extern unsigned int neonversion;
|
extern unsigned int neonversion;
|
||||||
|
|
||||||
char *timeval_to_string( struct timeval tv );
|
std::string TimevalToString(timeval tv);
|
||||||
std::string UriDecode( const std::string &encoded );
|
std::string UriDecode( const std::string &encoded );
|
||||||
void touch( const char *pathname );
|
void touch( const char *pathname );
|
||||||
|
|
||||||
|
|
|
@ -241,8 +241,9 @@ int main(int argc, const char *argv[], char **envp) {
|
||||||
|
|
||||||
time_t now = time(nullptr);
|
time_t now = time(nullptr);
|
||||||
char date_string[64];
|
char date_string[64];
|
||||||
|
tm now_tm = {};
|
||||||
strftime(date_string, sizeof(date_string)-1,
|
strftime(date_string, sizeof(date_string)-1,
|
||||||
"%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
|
"%a, %d %b %Y %H:%M:%S GMT", gmtime_r(&now, &now_tm));
|
||||||
|
|
||||||
fputs("Last-Modified: ", stdout);
|
fputs("Last-Modified: ", stdout);
|
||||||
fputs(date_string, stdout);
|
fputs(date_string, stdout);
|
||||||
|
|
|
@ -506,8 +506,10 @@ int main(int argc, char *argv[]) {
|
||||||
struct timeval timestamp = monitor->GetTimestamp(image_idx);
|
struct timeval timestamp = monitor->GetTimestamp(image_idx);
|
||||||
if ( verbose ) {
|
if ( verbose ) {
|
||||||
char timestamp_str[64] = "None";
|
char timestamp_str[64] = "None";
|
||||||
if ( timestamp.tv_sec )
|
if ( timestamp.tv_sec ) {
|
||||||
strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime(×tamp.tv_sec));
|
tm tm_info = {};
|
||||||
|
strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime_r(×tamp.tv_sec, &tm_info));
|
||||||
|
}
|
||||||
if ( image_idx == -1 )
|
if ( image_idx == -1 )
|
||||||
printf("Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000);
|
printf("Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue