перекрестная платформа timegm

Я использую Visual Studio c++ Compiler (2010), но библиотека имеет различную реализацию функций ANSI C и POSIX.

В чем разница между функцией ANSI C и реализацией Windows CRT? Например, в чем разница между tzset() и _tzset() или setenv() ans _setenv()? Кажется, что то же самое происходит одинаково...

Я использую msvc (2010), должен ли я предпочесть реализацию Windows CRT?

ИЗМЕНИТЬ 1

Ну, я хочу преобразовать в переносном стиле struct tm, выраженный в UTC в time_t, но нет никакого портативного способа сделать это. Я должен написать функцию для разных платформ (Android, Linux, Windows, Windows CE).

Я видел qaru.site/info/280378/... которая использует setenv, getenv и tzset

Edit2

К сожалению, после некоторого теста я обнаружил, что getenv("TZ") возвращает нулевой указатель на окна. Но почему так сложно преобразовать структуру времени UTC в time_t?

Редактировать 3

Из Boost я обнаружил этот фрагмент кода в boost/chrono/io/time_point_io.hpp. Надеюсь, это поможет мне.

inline int32_t is_leap(int32_t year)
{
  if(year % 400 == 0)
  return 1;
  if(year % 100 == 0)
  return 0;
  if(year % 4 == 0)
  return 1;
  return 0;
}
inline int32_t days_from_0(int32_t year)
{
  year--;
  return 365 * year + (year / 400) - (year/100) + (year / 4);
}
inline int32_t days_from_1970(int32_t year)
{
  static const int days_from_0_to_1970 = days_from_0(1970);
  return days_from_0(year) - days_from_0_to_1970;
}
inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day)
{
  static const int32_t days[2][12] =
  {
    { 0,31,59,90,120,151,181,212,243,273,304,334},
    { 0,31,60,91,121,152,182,213,244,274,305,335}
  };
  return days[is_leap(year)][month-1] + day - 1;
}

inline time_t internal_timegm(std::tm const *t)
{
  int year = t->tm_year + 1900;
  int month = t->tm_mon;
  if(month > 11)
  {
    year += month/12;
    month %= 12;
  }
  else if(month < 0)
  {
    int years_diff = (-month + 11)/12;
    year -= years_diff;
    month+=12 * years_diff;
  }
  month++;
  int day = t->tm_mday;
  int day_of_year = days_from_1jan(year,month,day);
  int days_since_epoch = days_from_1970(year) + day_of_year;

  time_t seconds_in_day = 3600 * 24;
  time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec;

  return result;
}

Ответ 1

Я использую следующий макрос в Windows:

#define timegm _mkgmtime

как _mkgmtime делает то же самое.

Ответ 2

Когда команда Дэвида Катлера начала работать над дизайном Windows NT, еще в 1989 году они еще не знали, какой апи будет доминировать. Таким образом, они создали три из них. Win32 была адаптирована к 16-битной версии Windows api. OS/2 была поддержана, операционная система, которая должна была заменить DOS, но не сделала этого. И Posix был третьим, добавил, потому что тогда правительство США уточнило, что они будут рассматривать только операционные системы, которые следуют за новым стандартом Posix.

Функция tzset(), о которой вы говорите, является слева от Posix api. Вы, вероятно, ошибочно написали putenv(), ту же историю. Подсистема не увенчалась успехом, Win32 выиграла битку api в большой степени, а поддержка Posix была удалена из Windows в 2001 году. Microsoft поддерживала поддержку функций Posix, но переименовала их с лидирующим подчеркиванием, поскольку они не являются частью стандарта C библиотеки. Вы должны получать предупреждения об устаревании, когда используете неиспользуемую версию функций. Похоже, вы #defined _CRT_NONSTDC_NO_DEPRECATE, чтобы подавить их. Лучше не делать этого. Поддерживайте стандартные функции библиотеки C.

Ответ 3

Для большинства функций, о которых я знаю, нет никакой разницы.

Подчеркивание имен должно подчеркнуть, что они не являются стандартными функциями C: AFAIK, в ANSI C нет функций tzset или setenv. Они в основном являются функциями POSIX, которые реализуются MS CRT в качестве вспомогательной возможности для переносимости из других операционных системы.

Но они не требуют совместимости с POSIX, поэтому подчеркивание. И поэтому вы должны быть осторожны и прочитать документацию MS об этих функциях... там есть демоны!

Ответ 4

Моя реализация timegm работает над окнами.

time_t timegm(struct tm * a_tm)
{
    time_t ltime = mktime(a_tm);
    struct tm tm_val;
    gmtime_s(&tm_val, &ltime);
    int offset = (tm_val.tm_hour - a_tm->tm_hour);
    if (offset > 12)
    {
        offset = 24 - offset;
    }
    time_t utc = mktime(a_tm) - offset * 3600;
    return utc;
}

Все должно быть в порядке.

Ответ 5

// Algorithm: http://howardhinnant.github.io/date_algorithms.html
int days_from_civil(int y, int m, int d)
{
    y -= m <= 2;
    int era = y / 400;
    int yoe = y - era * 400;                                   // [0, 399]
    int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  // [0, 365]
    int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           // [0, 146096]
    return era * 146097 + doe - 719468;
}

time_t timegm(tm const* t)     // It  does not modify broken-down time
{
    int year = t->tm_year + 1900;
    int month = t->tm_mon;          // 0-11
    if (month > 11)
    {
        year += month / 12;
        month %= 12;
    }
    else if (month < 0)
    {
        int years_diff = (11 - month) / 12;
        year -= years_diff;
        month += 12 * years_diff;
    }
    int days_since_1970 = days_from_civil(year, month + 1, t->tm_mday);

    return 60 * (60 * (24L * days_since_1970 + t->tm_hour) + t->tm_min) + t->tm_sec;
}

Это переносимый способ преобразования тм в UTC в time_t.

Обратите внимание, что он не изменяет/не нормализует структуру tm и не меняет никаких настроек tz.