У меня есть следующий код C, спрятанный для решения проблемы. Эффективность — не первое слово, которое приходит на ум (два вызова setenv()
, два вызова tzset()
), но стандартная библиотека C не позволяет сделать лучше:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static void time_convert(time_t t0, char const *tz_value)
{
char old_tz[64];
strcpy(old_tz, getenv("TZ"));
setenv("TZ", tz_value, 1);
tzset();
char new_tz[64];
strcpy(new_tz, getenv("TZ"));
char buffer[64];
struct tm *lt = localtime(&t0);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
setenv("TZ", old_tz, 1);
tzset();
printf("%ld = %s (TZ=%s)\n", (long)t0, buffer, new_tz);
}
int main(void)
{
time_t t0 = time(0);
char *tz = getenv("TZ");
time_convert(t0, tz);
time_convert(t0, "UTC0");
time_convert(t0, "IST-5:30");
time_convert(t0, "EST5");
time_convert(t0, "EST5EDT");
time_convert(t0, "PST8");
time_convert(t0, "PST8PDT");
}
В вашем исходном коде вам нужно беспокоиться о нормализации временной структуры после изменения часового смещения. Это можно сделать с помощью функции mktime()
. Вот программа, основанная на функции в вопросе, которая является чистым C и позволяет избежать проблем с возвратом указателя на локальную переменную (и #define
, заканчивающийся точкой с запятой):
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define PST (-8)
extern int getSecondSystemTime(char *buffer, size_t buflen);
int getSecondSystemTime(char *buffer, size_t buflen)
{
time_t rawtime = time(0);;
struct tm *timeinfo;
char t_buff[32];
timeinfo = gmtime(&rawtime);
timeinfo->tm_hour = timeinfo->tm_hour + PST;
time_t pst_time = mktime(timeinfo);
assert(pst_time != (time_t)-1);
int len = strftime(t_buff, sizeof(t_buff), "%Y-%m-%d %H:%M:%S", timeinfo);
assert(len != 0);
int rv = snprintf(buffer, buflen, "%ld = %s (%s)", (long)rawtime, t_buff,
"Pacific Time (US & Canada)");
assert(rv > 0);
return rv;
}
int main(void)
{
char buffer[128];
getSecondSystemTime(buffer, sizeof(buffer));
printf("%s\n", buffer);
return(0);
}
Очевидно, что лучший интерфейс будет передавать значение времени UTC и смещение часового пояса (в часах и минутах) в качестве аргументов. Несмотря на то, что мой компьютер работает в часовом поясе США/Тихоокеанского региона (или Америки/Лос-Анджелеса) по умолчанию, я тестировал с различными значениями TZ (включая США/Восточный, IST-05:30) и получил правильные значения; Я разумно убежден, основываясь на прошлом опыте, что расчет верен.
У меня есть другая программа, которая пытается проанализировать, является ли -1
, возвращенное из mktime()
, из-за ошибки или потому, что преобразованное время соответствует (time_t)-1
:
/* Attempt to determine whether time is really 1969-12-31 23:59:59 +00:00 */
static int unix_epoch_minus_one(const struct tm *lt)
{
printf("tm_sec = %d\n", lt->tm_sec);
if (lt->tm_sec != 59)
return(0);
printf("tm_min = %d\n", lt->tm_min);
/* Accounts for time zones such as Newfoundland (-04:30), India (+05:30) and Nepal (+05:45) */
if (lt->tm_min % 15 != 14)
return(0);
/* Years minus 1900 */
printf("tm_year = %d\n", lt->tm_year);
if (lt->tm_year != 69 && lt->tm_year != 70)
return(0);
printf("tm_mday = %d\n", lt->tm_mday);
if (lt->tm_mday != 31 && lt->tm_mday != 1)
return(0);
/* Months 0..11 */
printf("tm_mon = %d\n", lt->tm_mon);
if (lt->tm_mon != 11 && lt->tm_mon != 0)
return(0);
/* Pretend it is valid after all - though there is a small chance we are incorrect */
return 1;
}
person
Jonathan Leffler
schedule
27.12.2012
#define
; это почти неизбежно ошибка! - person Jonathan Leffler   schedule 27.12.2012temp
, которая уничтожается к тому времени, когда вызывающая функция получает возвращаемое значение... это не рецепт счастья. - person Jonathan Leffler   schedule 27.12.2012