web-dev-qa-db-ja.com

timegmクロスプラットフォーム

Visual Studio c ++コンパイラ(2010)を使用していますが、ライブラリにはANSICおよびPOSIXライブラリ関数の実装が異なります。

ANSIC機能とWindowsCRT実装の違いは何ですか?たとえば、tzset()_tzset()またはsetenv() ans _setenv()の違いは何ですか?同じように同じことをしているようです...

Msvc(2010)を使用していますが、Windows CRTの実装を優先する必要がありますか?

編集1

UTCで_time_t_で表現されたstruct tmを移植可能な方法で変換したいのですが、それを行う移植可能な方法はありません。さまざまなプラットフォーム(Android、Linux、Windows、Windows CE)用の関数を作成する必要があります。

私が見た このstackoverflowの投稿setenvgetenvtzsetを使用

Edit2

残念ながら、いくつかのテストの結果、getenv("TZ")がWindowsでnullポインタを返すことがわかりました。しかし、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;
}
_
15
elvis.dukaj

私はWindowsで次のマクロを使用しています。

#define timegm _mkgmtime

_ mkgmtime も同じです。

19
Naszta

DavidCutlerのチームがWindowsNTの設計を開始したとき、1989年に、どのapiが優勢になるかはまだわかりませんでした。それで彼らはそれらのthreeを作成しました。 Win32は、16ビットバージョンのWindowsAPIを改造したものです。 OS/2がサポートされていたが、オペレーティングシステムはDOSに取って代わるはずだったが、そうではなかった。また、Posixは3番目であり、当時の米国政府は、新しいPosix標準に従ったオペレーティングシステムの使用のみを検討することを指定したため、追加されました。

あなたが言及するtzset()関数は、PosixAPIからの残りです。同じ話で、おそらくputenv()のつづりを間違えたでしょう。サブシステムはうまくいきませんでした。Win32はAPIバトルに大いに勝ち、Posixサポートは2001年にWindowsから削除されました。MicrosoftはPosix関数のサポートを維持しましたが、標準の一部ではないため、先頭に下線を付けて名前を変更しました。 Cライブラリ。接頭辞のないバージョンの関数を使用すると、非推奨の警告が表示されるはずです。それらを抑制するために#defined_CRT_NONSTDC_NO_DEPRECATEのように聞こえます。そうしないのが最善です。標準Cライブラリ関数を優先します。

8
Hans Passant

私が知っているほとんどの関数については、違いはありません。

名前の下線は、これらがnot標準のC関数であることを強調するためにあります:AFAIK、ANSICにはtzset関数もsetenv関数もありません。ほとんどが他のオペレーティングシステムからの移植性を支援するためにMSCRTによって実装されるPOSIX関数。

しかし、彼らはPOSIXの互換性を主張していないので、アンダースコアが付けられています。そのため、これらの関数に関するMSのドキュメントに注意して読む必要があります...そこには悪魔がいます!

3
rodrigo
// 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のtmをtime_tに変換する移植可能な方法です。

Tm構造を変更/正規化せず、tz設定も変更しないことに注意してください。

2
Sergey D

私のtimegmの実装はWindowsで機能しています。

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;
}

大丈夫なはずです。

1
Siewca