質問
1970年1月1日午前0時(UTC)から経過した秒数として表される時刻(以前のtime()呼び出しの結果)があります。この時間に1日を追加するにはどうすればよいですか?
24 * 60 * 60を追加するとほとんどの場合に機能しますが、夏時間の間にオンまたはオフになると失敗します。つまり、24時間を追加したいのですが、23時間または25時間を追加したい場合があります。
説明のために-プログラム:
#include <time.h>
#include <iostream>
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
time_t time = base + i * 24 * 60 * 60;
std::cout << ctime(&time);
}
return 0;
}
プロデュース:
Sat Mar 11 08:00:00 2006
Sun Mar 12 09:00:00 2006
Mon Mar 13 09:00:00 2006
Tue Mar 14 09:00:00 2006
3月12日、13日、...の時間も午前8時にしたい。
FigBugの答えは、正しい方向を示してくれました。しかし、gmtimeの代わりにlocaltimeを使用する必要がありました。
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
std::cout << asctime(tm);
}
return 0;
}
お願い:
Sat Mar 11 08:00:00 2006
Sat Mar 12 08:00:00 2006
Sat Mar 13 08:00:00 2006
Sat Mar 14 08:00:00 2006
これは私が欲しいものです。 gmtimeを使用すると、14:00:00の時刻が表示されます
ただし、すべての日が土曜日であることに注意してください。また、3月32、33などになります。mktime関数をスローすると、開始した場所に戻ります。
#include <time.h>
#include <iostream>
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
time_t time = mktime(tm);
std::cout << asctime(tm);
}
return 0;
}
教えてください:
std::cout << ctime(&time);
不足しているもの???
OK、使用するFigBugの最新の提案を試しました:
Sat Mar 11 08:00:00 2006
Sun Mar 12 08:00:00 2006
Mon Mar 13 08:00:00 2006
Tue Mar 14 08:00:00 2006
asctimeではなく、同じ結果が得られます。だから、私のライブラリやコンパイラが台無しになっていると思います。 cygwinでg ++ 3.4.4を使用しています。ファイルをSolaris 5.8にコピーし、g ++ 3.3を使用してコンパイルしました。そこで正しい結果が得られました!実際、出力にctimeを使用してもasctimeを使用しても、正しい結果が得られます。
<*>Red Hut Linux(g ++ 3.4.6)でも(両方の出力関数で)正しい結果が得られます。
だから、Cygwinのバグに遭遇したと思います。
ご協力ありがとうございます...
解決
gmtime()を使用して time_t を struct tm
に変換します1日追加( tm_mday )
mktime()を使用して struct tm を time_t
に戻す詳細については、 time.h をご覧ください
編集:
試したところ、これは動作します:
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
time_t next = mktime(tm);
std::cout << ctime(&next);
}
return 0;
}
他のヒント
24 * 60 * 60を追加します。 UTCはDSTを使用しないため、DST中に失敗することはありません。
失敗する場合、コードのどこかでUTCを使用していません。タイムゾーンの依存関係を削除します。
FigBugのソリューションは毎回ほぼ動作しますが、DSTの修正が必要です: tm-<!> gt; tm_isdst = -1
tm_isdstの正または0の値 mktime()が最初に推測するようにします その夏時間 それぞれ、有効または無効です 指定された時間。負 tm_isdstの値により、mktime()が 夏時間かどうかを判断しよう 時間の節約は 指定された時間。
( mktime spec から引用)
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
tm->tm_isdst = -1; // don't know if DST is in effect, please determine
// this for me
time_t next = mktime(tm);
std::cout << ctime(&next);
}
return 0;
}
それ以外の場合、バグが発生します(2009年3月29日01:59:59から始まるモスクワの夏時間の例):
int main()
{
// 28 March 2009 05:00:00 GMT ( local - 08:00 (MSK) )
time_t base = 1238216400;
std::time_t start_date_t = base;
std::time_t end_date_t = base;
std::tm start_date = *std::localtime(&start_date_t);
std::tm end_date = *std::localtime(&end_date_t);
end_date.tm_mday += 1;
// end_date.tm_isdst = -1;
std::time_t b = mktime(&start_date);
std::time_t e = mktime(&end_date);
std::string start_date_str(ctime(&b));
std::string stop_date_str(ctime(&e));
cout << " begin (MSK) (DST is not active): " << start_date_str;
cout << " end (MSD) (DST is active): " << stop_date_str;
}
出力:
begin (MSK) (DST is not active): Sat Mar 28 08:00:00 2009
end (MSD) (DST is active): Sun Mar 29 09:00:00 2009
タイムスタンプをUTCに維持し、値を表示するときに指定したタイムゾーン(夏時間を含む)に変換すると、常に最高の結果が得られました。
これにより、このような手間が大幅に節約されます(プログラムがタイムゾーンに依存しなくなります。
非常に古い質問に対する新しい回答。
新しい答えの理由:この問題を解決するためのより良いツールがあり、シリアル<!> lt;-<!> gt;を最小化することで、エラーを起こしにくく、読みやすく、実際に効率的にします。フィールド変換。
新しい回答には、C ++ 11/14、<chrono>
、およびこの無料、オープンソース、タイムゾーンライブラリ。
コードは次のとおりです。
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
auto base = make_zoned("Pacific/Easter", sys_seconds{1142085600s});
for (int i = 0; i < 4; ++i)
{
std::cout << format("%a %b %d %T %Y %Z", base) << '\n';
base = base.get_local_time() + days{1};
}
}
まず、希望のタイムゾーンとUnixタイムタイムスタンプをペアにしてzoned_time
を作成します。
任意の形式でフォーマットされます。
また、1日の追加はタイムゾーンのローカルタイムシステムで行われ、夏時間を考慮に入れます。出力は次のとおりです。
Sat Mar 11 09:00:00 2006 -05
Sun Mar 12 09:00:00 2006 -06
Mon Mar 13 09:00:00 2006 -06
Tue Mar 14 09:00:00 2006 -06
判明したように、この出力はOPが望んだとおりではありません(要求された出力は毎日08:00:00です)。ただし、このライブラリを使用して、この日付の惑星全体の時間遷移を完全に調査しました。また、この日付に移行したタイムゾーンは太平洋/イースターのみです。そしてその移行は、前進ではなく、1時間後退することでした。これは、南半球のチリで使用されるタイムゾーンであり、3月のタイムフレームで1つがフォールバックします。
これは、現地時間ではなくUTCで算術演算を行うことで実証できます。これは、上記のプログラムを1行で微調整するだけです。
base = base.get_sys_time() + days{1};
base.get_sys_time()
ではなくbase.get_local_time()
を使用すると、算術は<!> quot; system time <!> quot;で実行されます。これは、うるう秒を無視したUTCです。そして、出力は次のように変わります。
Sat Mar 11 09:00:00 2006 -05
Sun Mar 12 08:00:00 2006 -06
Mon Mar 13 08:00:00 2006 -06
Tue Mar 14 08:00:00 2006 -06