10

日付を操作して将来の日付を作成しようとしていますが、夏時間が邪魔になり、時間を台無しにしています。

日付の翌月の最初の日の真夜中に移動するコードは次のとおりです。

+ (NSDate *)firstDayOfNextMonthForDate:(NSDate*)date
{
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    calendar.timeZone = [NSTimeZone systemTimeZone];
    calendar.locale = [NSLocale currentLocale];

    NSDate *currentDate = [NSDate dateByAddingMonths:1 toDate:date];
    NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                                    fromDate:currentDate];

    [components setDay:1];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];

    return [calendar dateFromComponents:components];
}

+ (NSDate *) dateByAddingMonths: (NSInteger) monthsToAdd toDate:(NSDate*)date
{
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    calendar.timeZone = [NSTimeZone systemTimeZone];
    calendar.locale = [NSLocale currentLocale];

    NSDateComponents * months = [[NSDateComponents alloc] init];
    [months setMonth: monthsToAdd];

    return [calendar dateByAddingComponents: months toDate: date options: 0];
}

日付でメソッドを繰り返し実行すると、日付が得られます。

2013-02-01 00:00:00 +0000
2013-03-01 00:00:00 +0000
2013-03-31 23:00:00 +0000 should be 2013-04-01 00:00:00 +0000
2013-04-30 23:00:00 +0000 should be 2013-05-01 00:00:00 +0000

私の最初の考えは使用しないことsystemTimeZoneでしたが、それは違いを生むようには見えませんでした. 夏時間の変更を考慮せずに時間を一定にする方法についてのアイデアはありますか?

4

4 に答える 4

8

特定のカレンダーの日付/時刻について、それが表す実際の時刻 (エポックからの秒数) を予測することは原則として不可能です。タイム ゾーンが変更され、DST ルールが変更されます。それは人生の事実です。オーストラリアでは、DST には苦難の歴史があります。DST 規則は、イスラエルでは非常に予測不可能でした。最近、米国で DST ルールが変更され、カレンダーの日付ではなく秒を保存していた Microsoft にとって大きな頭痛の種になりました。

NSDateあなたが意味するときは決して保存しないでくださいNSDateComponents。「2013 年 5 月 1 日のロンドン」という意味であれば、「2013 年 5 月 1 日のロンドン」をデータベースに保存します。NSDate次に、実際のイベントにできるだけ近いオフを計算します。NSDateComponentsカレンダーのこと (月など) が気になる場合は、 を使用してすべてのカレンダー計算を行います。NSDate本当に秒だけを気にする場合にのみ、計算を行ってください。

編集: 多くの非常に有用な背景については、日付と時刻のプログラミング ガイドを参照してください。

カレンダーの構成要素に関するもう 1 つの注意点: 「2013 年 5 月 1 日ロンドンで」と言うとき、それは「5 月 1 日の午前 0 時」という意味ではありません。実際には意味のないカレンダー コンポーネントを追加しないでください。

于 2013-01-28T21:15:40.417 に答える
4

プログラムがログに出力しているのは、現地時間ではなく GMT 時間であることに注意してください。したがって、GMT が 1 時間ずれているローカル タイム ゾーンの DST への切り替え後の日付は正しいです。

于 2013-01-28T20:54:19.003 に答える
3

私は同じ問題を抱えていましたが、実際には問題ではないと言っている人々 (関連するスレッドで見たように) は状況を助けません. この種の問題は、タイムゾーンと DST に対処しなければならないときはいつでも痛いものであり、私は毎回それを再学習しなければならないと常に感じています.

可能な限りエポック タイムを扱っていましたが (これはグラフ作成アプリケーションです)、NSDate と NSCalendar を使用する必要がある場合がありました (つまり、軸ラベルの書式設定と、カレンダーの月、四半期、年をマークするため)。カレンダーなどにさまざまなタイムゾーンを設定しようとして、1日ほどこれに苦労しました。

最終的に、アプリ デリゲートの次のコード行が非常に役立つことがわかりました。

// prevent DST bugs by setting default timezone for app
    if let utcZone = NSTimeZone(abbreviation: "UTC") {
        NSTimeZone.setDefaultTimeZone(utcZone)
    }

これに加えて、ソース データをサニタイズする必要があったため、NSDateFormatter受信データで を使用するたびに、そのタイム ゾーンをデータ ソースの正しいタイム ゾーン (私の場合は GMT) に設定するようにしました。これにより、データ ソースの厄介な DST の問題が解消され、DST を気にすることなく、結果として得られるすべての NSDates を適切にエポック時間に変換できるようになります。

于 2016-03-03T11:42:40.623 に答える