C код для получения смещения по местному времени в минутах относительно UTC?
Я не нашел тривиального способа получить смещение времени в минутах между местным временем и временем UTC.
сначала я намеревался использовать tzset()
но он не обеспечивает летнее время. Согласно справочной странице, это просто целое число, отличное от нуля, если дневная экономия света действует. Хотя обычно это час, в какой-то стране это может быть полчаса.
Я бы предпочел избежать вычисления разницы во времени между текущим UTC, возвращаемым gmtime()
и localtime()
.
более общее решение дало бы мне эту информацию для указанного местоположения и положительного значения time_t или, по крайней мере, локально.
изменить 1: вариант использования-получить правильное смещение по местному времени дляhttps://github.com/chmike/timez. Кстати, если вы думали, что функции libc для управления временем в порядке, прочитайте это https://rachelbythebay.com/w/2013/03/17/time/.
изменить 2: лучшее и простое решение, которое у меня есть до сих пор, чтобы вычислить смещение времени в UTC в минутах, -
// Bogus: assumes DST is always one hour
tzset();
int offset = (int)(-timezone / 60 + (daylight ? 60 : 0));
проблема состоит в том, чтобы определить реальное время экономии света.
Edit 3: вдохновленный ответом @trenki, Я придумал следующее решение. Это хак в том, что он трюки mktime()
рассмотреть выход gmtime()
как с локальным. Результат является неточным, когда изменение DST находится в промежутке времени между UTC время и localtime.
#include <stdio.h>
#include <time.h>
int main()
{
time_t rawtime = time(NULL);
struct tm *ptm = gmtime(&rawtime);
// Request that mktime() looksup dst in timezone database
ptm->tm_isdst = -1;
time_t gmt = mktime(ptm);
double offset = difftime(rawtime, gmt) / 60;
printf("%fn", offset);
return 0;
}
4 ответов
... чтобы получить смещение по местному времени ... относительно UTC?
@Serge Ballesta ответ хороший. Поэтому я решил проверить его и прояснить некоторые детали. Я бы опубликовал комментарий, но, очевидно, слишком большой для этого. Я только использовал его для своего часового пояса, но хотя другие могут захотеть попробовать на своей машине и зоне.
Я сделал для сообщества wiki, чтобы не набрать репутацию. имитация-самая искренняя форма лесть!--10-->
этот ответ сродни @trenki за исключением того, что он вычитает рядом struct tm
значения вместо предположения, что сдвиг DST равен 1 часу и time_t
- время в секундах.
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
// return difference in **seconds** of the tm_mday, tm_hour, tm_min, tm_sec members.
long tz_offset_second(time_t t) {
struct tm local = *localtime(&t);
struct tm utc = *gmtime(&t);
long diff = ((local.tm_hour - utc.tm_hour) * 60 + (local.tm_min - utc.tm_min))
* 60L + (local.tm_sec - utc.tm_sec);
int delta_day = local.tm_mday - utc.tm_mday;
// If |delta_day| > 1, then end-of-month wrap
if ((delta_day == 1) || (delta_day < -1)) {
diff += 24L * 60 * 60;
} else if ((delta_day == -1) || (delta_day > 1)) {
diff -= 24L * 60 * 60;
}
return diff;
}
void testtz(void) {
long off = -1;
int delta = 600;
for (time_t t = 0; t < LONG_MAX-delta; t+=delta) {
long off2 = tz_offset_second(t);
// Print time whenever offset changes.
if (off != off2) {
struct tm utc = *gmtime(&t);
printf("%10jd %04d-%02d-%02dT%02d:%02d:%02dZ\n", (intmax_t) t,
utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday,
utc.tm_hour, utc.tm_min, utc.tm_sec);
struct tm local = *localtime(&t);
off = off2;
printf("%10s %04d-%02d-%02d %02d:%02d:%02d %2d %6ld\n\n", "",
local.tm_year + 1900, local.tm_mon + 1, local.tm_mday,
local.tm_hour, local.tm_min, local.tm_sec, local.tm_isdst ,off);
fflush(stdout);
}
}
puts("Done");
}
выход
v----v Difference in seconds
0 1970-01-01T00:00:00Z
1969-12-31 18:00:00 0 -21600
5731200 1970-03-08T08:00:00Z
1970-03-08 03:00:00 1 -18000
26290800 1970-11-01T07:00:00Z
1970-11-01 01:00:00 0 -21600
...
2109222000 2036-11-02T07:00:00Z
2036-11-02 01:00:00 0 -21600
2120112000 2037-03-08T08:00:00Z
2037-03-08 03:00:00 1 -18000
2140671600 2037-11-01T07:00:00Z
2037-11-01 01:00:00 0 -21600
Done
этот код C вычисляет локальное смещение времени в минутах относительно UTC. Предполагается, что DST всегда смещен на один час.
#include <stdio.h>
#include <time.h>
int main()
{
time_t rawtime = time(NULL);
struct tm *ptm = gmtime(&rawtime);
time_t gmt = mktime(ptm);
ptm = localtime(&rawtime);
time_t offset = rawtime - gmt + (ptm->tm_isdst ? 3600 : 0);
printf("%i\n", (int)offset);
}
он использует gmtime и localtime, хотя. Почему вы не хотите использовать эти функции?
IMHO единственный надежный и портативный способ-использовать localtime
и gmtime
и вручную вычислить дельту в минуту, потому что эти 2 функции существуют во всех известных системах. Например:
int deltam() {
time_t t = time(NULL);
struct tm *loc = localtime(&t);
/* save values because they could be erased by the call to gmtime */
int loc_min = loc->tm_min;
int loc_hour = loc->tm_hour;
int loc_day = loc->tm_mday;
struct tm *utc = gmtime(&t);
int delta = loc_min - utc->tm_min;
int deltaj = loc_day - utc->tm_mday;
delta += (loc_hour - utc->tm_hour) * 60;
/* hack for the day because the difference actually is only 0, 1 or -1 */
if ((deltaj == 1) || (deltaj < -1)) {
delta += 1440;
}
else if ((deltaj == -1) || (deltaj > 1)) {
delta -= 1440;
}
return delta;
}
остерегайтесь, я не стал проверять все возможные случаи, но это может быть отправной точкой для вашего требования.
поддерживает ли функция strftime() вашей системы %z
и %Z
спецификаторы? На FreeBSD,
%Z is replaced by the time zone name. %z is replaced by the time zone offset from UTC; a leading plus sign stands for east of UTC, a minus sign for west of UTC, hours and minutes follow with two digits each and no delimiter between them (common form for RFC 822 date headers).
и я могу использовать это, чтобы напечатать это:
$ date +"%Z: %z"
CEST: +0200
ISO C99 имеет это в 7.23.3.5 в strftime
функции:
%z is replaced by the offset from UTC in the ISO 8601 format ‘‘−0430’’ (meaning 4 hours 30 minutes behind UTC, west of Greenwich), or by no characters if no time zone is determinable. [tm_isdst] %Z is replaced by the locale’s time zone name or abbreviation, or by no characters if no time zone is determinable. [tm_isdst]