7

次のコードを検討してください。

time_t t;
t = time( NULL );
elog << "timezone: " << getenv( "TZ" ) 
     << ", current local time: " << asctime( localtime( &t ));

MSVCを使用してこのコードをビルドし、Windows DOSシェルで実行すると、正しい現地時間が取得されます。

timezone: , current local time: Wed Jul 25 13:05:08 2012

しかし、bashのようなcygwinシェルで同じプログラムを実行すると、このコードはGMTを返します。

timezone: America/New_York, current local time: Wed Jul 25 18:05:08 2012

このプログラムをLinuxまたはOsXで実行すると、正しい現地時間も返されます。

なんで?

@Update:1年後のことですが、以下の回答が常に機能するとは限りません。

一部のプログラムでは、TZの設定を解除しても常に機能するとは限らないようです。どうしてか分かりません。ただし、面倒な回避策があります。基本的に、TZの設定を解除した直後に、現地時間が実際にGMTを返さないことを確認する必要がありますが、実際にGMTタイムゾーンにいない場合に限り、localtime()またはを呼び出すときにtime_tの手動調整を計算します。時間を作る()

u64 localTimeOffset = 0;

static void unsetTz()
{
   static bool unsetTZ = false;
   if ( !unsetTZ )
   {
      putenv( "TZ=" );
      unsetTZ = true;

      // unsetting TZ does not always work. So we have to check if it worked
      // and make a manual adjustment if it does not. For long running programs
      // that may span DST changes, this may cause the DST change to not take 
      // effect.
      s32 tzOffset = getTzOffset();

      if ( tzOffset )
      {
         static char timeBuf[48];
         char* s = &(timeBuf[0]);
         struct tm* timeInfoGMT;
         struct tm* timeInfoLocal;

         time_t zero = 86400;
         timeInfoGMT = gmtime( &zero );
         u32 GMTHour = timeInfoGMT->tm_hour;

         timeInfoLocal = localtime( &zero );
         u32 localHour = timeInfoLocal->tm_hour;

         if ( localHour == GMTHour )
         {
            // unsetting tz failed. So we have to make a manual adjustment
            localTimeOffset = tzOffset * 60 * 60;
         }
      }
   }
}

s32 getTzOffset()
{
   TIME_ZONE_INFORMATION tzInfo;
   GetTimeZoneInformation( &tzInfo );
   s32 tz = ( tzInfo.Bias / 60 );
   return tz;
}

現地時間への呼び出し:

  time_t t = getAtTimeFromSomewhere();
  t -= localTimeOffset;
  timeInfo = localtime( &t );

maketimeの呼び出し:

 struct tm timestr;
 makeATMFromAStringForExample( time, timestr );
 time_t timet = mktime( &timestr );
 timet += localTimeOffset;

良い時代。

4

3 に答える 3

11

これは私が理解するのに少し時間がかかりました、そして私はそれが他の人に役立つことを望んでいます。

のようなPOSIX関数localtimeは、環境変数を使用して、TZ使用するタイムゾーンを決定します。が設定されていない場合TZ、システムのデフォルトのタイムゾーンが使用されます。

LinuxまたはOSXで実行している場合、TZは正しく設定されており、すべてが機能します。このプログラムをWindowsのシェルで実行すると、TZが設定されていないため、関数はオペレーティングシステムのデフォルトのタイムゾーンを返し、これも正しい結果を生成します。

Cygwinシェルで実行すると、TZが設定されますが、MSVCを使用してプログラムをビルドしたため、MSVC独自のstdcライブラリを使用して、CygwinのTZ変数を解釈できません。したがって、デフォルトではGMTになります。

プログラムがCygwinの下でGCCを使用して構築されていれば、Cygwinシェルで正しく機能するはずです。

したがって、答えは、のようなPOSIX時間関数を呼び出すプログラムでlocaltime()、時間関数をCygwinシェルのすぐ下で機能させたい場合は、設定を解除する必要があることを確認することですTZ

私はそのようにそれをしました:

void getLocalTime()
{
   #ifdef WIN32
   static bool unsetTZ = false;
   if ( !unsetTZ )
   {
      putenv( "TZ=" );
      unsetTZ = true;
   }
   #endif // !WIN32

   time_t t;
   t = time( NULL );
   elog << "timezone: " << getenv( "TZ" ) 
        << ", current local time: " << asctime( localtime( &t ));
}
于 2012-07-25T17:15:42.233 に答える
1

Cygwinシェルでの使用export TZ=""が最善の方法かもしれません。

@Update
こんにちは、Tunaki。編集ありがとうございます!

于 2016-09-03T04:04:43.167 に答える
0

structtmにtm_isdstフラグを設定してみてください。

夏時間フラグ(tm_isdst)は、夏時間が有効な場合はゼロより大きく、夏時間が有効でない場合はゼロより大きく、情報が利用できない場合はゼロ未満です。

私がよく覚えているなら、Windowsでは正しく動作するために-1でなければなりません。

于 2012-07-25T17:26:10.890 に答える