简体   繁体   English

在编译时更改 libc 时区

[英]Changing the timezone in libc time at compile time

We have firmware that will be deployed on devices all over the world and that will be synced to UTC by a host device.我们的固件将部署在世界各地的设备上,并将由主机设备同步到 UTC。 To track time, we end up converting between struct tm and time_t (Unix time) because we use a hardware RTC whose registers closely mirror struct tm , but any time-based operations are done on Unix time.为了跟踪时间,我们最终在struct tmtime_t (Unix 时间)之间进行转换,因为我们使用了一个硬件 RTC,其寄存器与struct tm非常相似,但是任何基于时间的操作都是在 Unix 时间完成的。 However, when we use mktime it attempts to put everything into localtime , which is not UTC on the build system.但是,当我们使用mktime时,它会尝试将所有内容放入localtime ,这不是构建系统上的 UTC。 We could just add an offset, but it would be easier to just tell time.h that our local time should be UTC, since the device is otherwise agnostic to the local time.我们可以只添加一个偏移量,但只告诉time.h我们的本地时间应该是 UTC 会更容易,因为设备与本地时间无关。

Is there a (non-invasive) way to do this other than changing the local time on the build system to UTC?除了将构建系统上的本地时间更改为 UTC 之外,是否有(非侵入性)方法可以做到这一点? Like, can we somehow use tzset to inject this data?就像,我们可以以某种方式使用tzset来注入这些数据吗? Or just set TZ to something?或者只是将TZ设置为什么? I'm having difficulty understanding how I would set TZ if I just wanted UTC.如果我只想要 UTC,我很难理解如何设置TZ

However, when we use mktime it attempts to put everything into localtime ...但是,当我们使用mktime时,它会尝试将所有内容都放入localtime时间...

The compiler's time zone setting at compile time is irrelevant to how code handles time at run time.编译器在编译时的时区设置与代码在运行时如何处理时间无关。

The easiest way to avoid local time in conversions is to hope your compiler offers struct_tm (UTC) to time_t , instead of using mktime() (time zone dependent) as an extension like time_t timegm(struct tm *tm) .在转换中避免本地时间的最简单方法是希望您的编译器为time_t提供struct_tm (UTC),而不是使用mktime() (取决于时区)作为time_t timegm(struct tm *tm)类的扩展。

There is no simple standard solution.没有简单的标准解决方案。 Tricks with divining the offset via locatime(), gmtime() fail corner cases.通过locatime(), gmtime()计算偏移量的技巧会失败。


IMO, to convert struct_tm (UTC) to UNIX time time_t , simply write that code and get it reviewed. IMO,要将struct_tm (UTC) 转换为 UNIX 时间time_t ,只需编写该代码并对其进行审核。 It is not that hard as there are few corner cases (aside from overflow).这并不难,因为很少有极端情况(除了溢出)。

Some sample code to change int year, int month, int day (0:00:00) to MJD to get OP started.一些示例代码将int year, int month, int day (0:00:00) 更改为MJD以启动 OP。

#include <stdint.h>
static const short DaysMarch1ToBeginingOfMonth[12] = { //
    0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337};
#ifndef INT32_C
#define INT32_C(x) ((int_least32_t)1*(x))
#endif
#define DaysPer400Years   (INT32_C(365)*400 + 97)
#define DaysPer100Years   (INT32_C(365)*100 + 24)
#define DaysPer4Years     (365*4    +  1)
#define DaysPer1Year      365
#define MonthsPerYear     12
#define MonthsPer400Years (12*400)
#define MonthMarch        3
#define mjdOffset         0xA5BE1
#define mjd1900Jan1       15020
// November 17, 1858

// Example: 2015 December 31 -->  ymd_to_mjd(2015, 12, 31)
int2x ymd_to_mjd(int year, int month, int day) {
  // int2x is a type twice as wide as int to handle extreme int values.
  // Use int (at least 32-bit) to handle common values.
  int2x year2x = year;

  year2x += month / MonthsPerYear;
  month %= MonthsPerYear;
  // Adjust for month/year to Mar ... Feb
  while (month < MonthMarch) {
    month += MonthsPerYear;
    year2x--;
  }

  int2x d = (year2x / 400) * DaysPer400Years;
  int y400 = (int) (year2x % 400);
  d += (y400 / 100) * DaysPer100Years;
  int y100 = y400 % 100;
  d += (y100 / 4) * DaysPer4Years;
  int y4 = y100 % 4;
  d += y4 * DaysPer1Year;
  d += DaysMarch1ToBeginingOfMonth[month - MonthMarch];
  d += day;
  // November 17, 1858 == MJD 0
  d--;
  d -= mjdOffset;
  return d;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM