获取相对于UTC的本地时间偏移(以分钟为单位)的C代码?

获取相对于UTC的本地时间偏移(以分钟为单位)的C代码?,c,time,offset,utc,C,Time,Offset,Utc,我没有找到一种简单的方法来获取本地时间和UTC时间之间的时间偏移量(以分钟为单位) 起初我打算使用tzset(),但它不提供夏令时。根据手册页,如果日光节约生效,它只是一个与零不同的整数。虽然通常是一小时,但在某些国家可能是半小时 我希望避免计算gmtime()和localtime()返回的当前UTC之间的时差 一个更一般的解决方案将为我提供指定位置和正时间值的信息,或者至少是局部信息 编辑1:用例是获取正确的本地时间偏移。 顺便说一句,如果您认为操纵时间的libc函数还可以,请阅读以下内容 编

我没有找到一种简单的方法来获取本地时间和UTC时间之间的时间偏移量(以分钟为单位)

起初我打算使用
tzset()
,但它不提供夏令时。根据手册页,如果日光节约生效,它只是一个与零不同的整数。虽然通常是一小时,但在某些国家可能是半小时

我希望避免计算
gmtime()
localtime()
返回的当前UTC之间的时差


一个更一般的解决方案将为我提供指定位置和正时间值的信息,或者至少是局部信息

编辑1:用例是获取正确的本地时间偏移。 顺便说一句,如果您认为操纵时间的libc函数还可以,请阅读以下内容

编辑2:到目前为止,计算UTC时间偏移量(以分钟为单位)的最佳最简单解决方案是

// Bogus: assumes DST is always one hour
tzset();
int offset = (int)(-timezone / 60 + (daylight ? 60 : 0));
问题是要确定实际的日间节能时间

编辑3:受的启发,我想出了以下解决方案。这是一个黑客程序,它的代码<>代码> MKTime](/Cord>)考虑“代码”> GMSTIME()/<代码>的输出作为LoalalTimes。当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("%f\n", offset);
    return 0;
}
#包括
#包括
int main()
{
time\u t rawtime=时间(空);
struct tm*ptm=gmtime(&rawtime);
//请求在时区数据库中使用mktime()looksup dst
ptm->tm_isdst=-1;
时间\u t gmt=mktime(ptm);
双偏移量=difftime(rawtime,gmt)/60;
printf(“%f\n”,偏移量);
返回0;
}

系统的strftime()函数是否支持
%z
%z
说明符?在FreeBSD上

我可以用这个来打印这个:

$ date +"%Z: %z"
CEST: +0200
ISO C99在7.23.3.5的
strftime
功能中有此功能:


此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);
}
#包括
#包括
int main()
{
time\u t rawtime=时间(空);
struct tm*ptm=gmtime(&rawtime);
时间\u t gmt=mktime(ptm);
ptm=本地时间(&rawtime);
时间偏移=原始时间-gmt+(ptm->tm isdst?3600:0);
printf(“%i\n”,(int)偏移量);
}

但它使用gmtime和localtime。你为什么不想使用这些函数呢?

我想,唯一简单方便的方法是使用
localtime
gmtime
并在几分钟内手动计算增量,因为这两个函数存在于所有已知系统上。例如:

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;
}
int deltam(){
时间t=时间(空);
struct tm*loc=本地时间(&t);
/*保存值,因为可以通过调用gmtime擦除这些值*/
int loc_min=loc->tm_min;
int loc\U hour=loc->tm\U hour;
int loc\U day=loc->tm\U mday;
struct tm*utc=gmtime(&t);
int delta=loc_min-utc->tm_min;
int deltaj=loc\U day-utc->tm\U mday;
增量+=(当地时间-utc->tm时间)*60;
/*因为实际差异只有0、1或-1*/
如果((deltaj==1)| |(deltaj<-1)){
delta+=1440;
}
else如果((deltaj==-1)| |(deltaj>1)){
delta-=1440;
}
返回三角洲;
}
当心,我并没有测试所有可能的角落案例,但这可能是您需求的起点

。。。要获取本地时间偏移。。。相对于UTC

答案是好的。所以我想我会测试它并清理一些细节。我可能会发表评论,但显然太大了。我只在我的时区使用它,但其他人可能想在他们的机器和时区上试用

我访问社区维基是为了不获得代表

这个答案类似于,只是它减去附近的
struct tm
值,而不是假设DST班次为1小时,
time\u 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");
}

我想为这个问题提供另一个答案,AFAICS也处理IDL

此解决方案取决于
timegm
mktime
。在Windows上,可以从CRT中以
\u mkgmtime
的形式获得
timegm
,换句话说,定义一个条件宏

#if _WIN32
#    define timegm _mkgmtime
#endif

int local_utc_offset_minutes ( ) {
    time_t t  = time ( NULL );
    struct tm * locg = localtime ( &t );
    struct tm locl;
    memcpy ( &locl, locg, sizeof ( struct tm ) );
    return (int)( timegm ( locg ) - mktime ( &locl ) ) / 60;
}

你为什么需要这个?更多地解释上下文;为什么您不能简单地使用
gmtime
localtime
并改变它们的
struct tm
?为什么您的用户会关心本地时间偏移?还有很多奇怪的情况(例如除夕夜…),你的问题很可能是操作系统特有的。。。AFAIK,不在标准C99中,但在POSIX@BasileStarynkevitch区域设置在C99中,甚至C89也有
strftime
,可惜只有
%Z
,而不是
%Z
“通用解决方案将为指定位置提供此信息”-->您希望如何指定位置?纬度/经度?现在你需要一张时区地图。由于地图随时间而变化,现在需要地图的历史记录。相反,建议使用简单设计来实现“特定时区的通用解决方案”。@BasileStarynkevitch它适用于此小型库:。这是一项正在进行的工作。我仍然需要验证一些东西的有效性,比如分钟时间偏移分辨率。我的问题不是针对操作系统的。我希望该库可以在Windows或Linux上使用。在Unix和GNU上,tm结构具有保存请求信息的TMgmtoff字段。这将是获取信息的一种方法。有点复杂,但它会起作用。但举例来说,VisualStudio不支持C99。不确定风投2015,但这是一个众所周知的问题。我更愿意避免对C99的依赖。解析文本
“-0030”
(和其他)需要小心以正确应用符号。例如,
sscanf(“-0030”、%c%2d%2d”、&sign、&hour、&min);增量=(符号='-'?-1:1)*(小时*60+分钟)#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
#if _WIN32
#    define timegm _mkgmtime
#endif

int local_utc_offset_minutes ( ) {
    time_t t  = time ( NULL );
    struct tm * locg = localtime ( &t );
    struct tm locl;
    memcpy ( &locl, locg, sizeof ( struct tm ) );
    return (int)( timegm ( locg ) - mktime ( &locl ) ) / 60;
}