NSDate一日の始まりと一日の終わり


104
    -(NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];

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

    return [cal dateFromComponents:components];

}

-(NSDate *)endOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:(  NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];

    [components setHour:23];
    [components setMinute:59];
    [components setSecond:59];

    return [cal dateFromComponents:components];

}

私が呼び出すとき:[self endOfDay:[NSDate date]]; 私は月の最初を取得します...なぜですか?最初の日付の最初の秒(beginningOfDay:date1)から2番目の日付の最後の秒(endOfDay:Date2)までの間隔が必要なので、この2つの方法を使用します...


2
時間をUTC時刻をゼロに設定する場合は、timeIntervalSince ...を取得し、時間を切り捨ててから、NSDateに戻す簡単な方法です。タイムゾーンのsecondsFromGMTで時間間隔を最初に調整し、切り捨てた後、反対の方法で調整すると、これは別のタイムゾーンでも機能します。(1日の終わりは明らかに23:59:59.999後であり、時間間隔がある間に単純な加算で取得できます。)
Hot Licks

「1日の終わり」を実際の終わり(この場合は1秒)の前の任意の時間として指定することは、問題のあるソフトウェアのレシピのように見えます。1 msを使用すると、グリッチの頻度が少なくなります。または、23時間を使用して、バグを見つけやすくすることもできます。:-)
エドワードブレイ

回答:


33

あなたは、不足しているNSDayCalendarUnit

NSDateComponents *components = [cal components:( NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];

1
日コンポーネントを追加すると、前日の23時になるという奇妙な動作があります。
マイクM

3
@マイクはタイムゾーンを使用:components.timeZone = [NSTimeZone timeZoneWithName:@ "GMT"];
dimaxyu 2014

@dimaxyuは正しいです。迅速に:components.timeZone = NSTimeZone(name: "GMT")
Tom Bevelander

220

1日の始まり/ 1日の終わり— Swift 4

  // Extension

extension Date {
    var startOfDay: Date {
        return Calendar.current.startOfDay(for: self)
    }

    var endOfDay: Date {
        var components = DateComponents()
        components.day = 1
        components.second = -1
        return Calendar.current.date(byAdding: components, to: startOfDay)!
    }

    var startOfMonth: Date {
        let components = Calendar.current.dateComponents([.year, .month], from: startOfDay)
        return Calendar.current.date(from: components)!
    }

    var endOfMonth: Date {
        var components = DateComponents()
        components.month = 1
        components.second = -1
        return Calendar.current.date(byAdding: components, to: startOfMonth)!
    }
}

// End of day = Start of tomorrow minus 1 second
// End of month = Start of next month minus 1 second

1
NSYearCalendarUnitNSMonthCalendarUnit、およびNSDayCalendarUnitiOSの8.で廃止されておりNSCalendarUnitYearNSCalendarUnitMonthそして、NSCalendarUnitDay代わりに!
Tブランク

6
1日の始めには、iOS8以降の場合は[[NSCalendar currentCalendar] startOfDayForDate:...]を使用します
GingerBreadMane

5
これは、現在のタイムゾーンでstartOfDayを返します。NSDateはUTCであることが期待されていますが、このコンバーターはデフォルトのタイムゾーンに修正された時刻を返します。
Tom Bevelander 2016

3
endOfDayがオプションなのはなぜですか?endOfDayがnilになる可能性があるのに、startOfDayがnilでない状況はありますか?
Mansurov Ruslan 2017

1
だから、あなたはこれを使用する方法に応じて、あなたは日の両端と始まりの間に1秒のギャップが気にdeveloper.apple.com/documentation/foundation/nsdate/...
atlex2

29

スウィフト5 シンプルで正確な答え。

開始時間:00:00:00

終了時間:23:59:59.5

let date = Date() // current date or replace with a specific date
let calendar = Calendar.current
let startTime = calendar.startOfDay(for: date)
let endTime = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: date)

追加

let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: noon)!
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: noon)!
let specificDate = Date("2020-01-01")

extension Date {
    init(_ dateString:String) {
        let dateStringFormatter = DateFormatter()
        dateStringFormatter.dateFormat = "yyyy-MM-dd"
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
        let date = dateStringFormatter.date(from: dateString)!
        self.init(timeInterval:0, since:date)
    }
}

2
これはどう違いlet dateAtEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())ますか?
Andres Canella

1
変わりはない 。
8月

21

iOS 8以降では、これは非常に便利です。できるよ:

let startOfDay = NSCalendar.currentCalendar().startOfDayForDate(date)

一日の終わりを取得するには、NSCalendarメソッドを23時間59分59秒だけ使用します。これは、一日の終わりの定義に応じて異なります。

// Swift 2.0
let components = NSDateComponents()
components.hour = 23
components.minute = 59
components.second = 59
let endOfDay = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: startOfDay, options: NSCalendarOptions(rawValue: 0))

日付の数学

Apple iOS NSCalendarドキュメント。(セクション:カレンダー計算を参照)

NSHipsterによって議論されたNSCalendarメソッド


17

NSDateのSwift拡張機能:

Swift 1.2

extension NSDate {

    func beginningOfDay() -> NSDate {
        var calendar = NSCalendar.currentCalendar()
        var components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: self)
        return calendar.dateFromComponents(components)!
    }

    func endOfDay() -> NSDate {
        var components = NSDateComponents()
        components.day = 1
        var date = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: self.beginningOfDay(), options: .allZeros)!
        date = date.dateByAddingTimeInterval(-1)!
        return date
    }
}

Swift 2.0

extension NSDate {

    func beginningOfDay() -> NSDate {
        let calendar = NSCalendar.currentCalendar()
        let components = calendar.components([.Year, .Month, .Day], fromDate: self)
        return calendar.dateFromComponents(components)!
    }

    func endOfDay() -> NSDate {
        let components = NSDateComponents()
        components.day = 1
        var date = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: self.beginningOfDay(), options: [])!
        date = date.dateByAddingTimeInterval(-1)
        return date
    }
}

秒を-1に設定し、dateByAddingTimeIntervalを使用せずに同じ値を取得できます
Ben Sinclair

タイムゾーンの問題を回避するには、以下を追加します。components.timeZone= NSTimeZone(name: "GMT")
Tom Bevelander

12

スウィフト5.1 - XCodeの11Date、クラスの代わりに、NSDateCalenderの代わりに、NSCalender

extension Date {

    var startOfDay : Date {
        let calendar = Calendar.current
        let unitFlags = Set<Calendar.Component>([.year, .month, .day])
        let components = calendar.dateComponents(unitFlags, from: self)
        return calendar.date(from: components)!
   }

    var endOfDay : Date {
        var components = DateComponents()
        components.day = 1
        let date = Calendar.current.date(byAdding: components, to: self.startOfDay)
        return (date?.addingTimeInterval(-1))!
    }
}

使用法:

    let myDate = Date()
    let startOfDate = myDate.startOfDay
    let endOfDate = myDate.endOfDay

Date遊び場で試してみると、エラーの宣言されていない型が表示されます
John Doe

1
ここでうまくいきます。UIKitをインポートしましたimport UIKitか?
ベン

2
@Ben Date and CalendarはUIKitにはなくFoundationにありますが、UIKitはFoundationをインポートします
Arbitur

4

コンポーネントをゼロに設定する必要はありません。無視してください:

-(NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date];
    return [calendar dateFromComponents:components];
}

2
「新しく」利用可能:[calendar startOfDayForDate:date]-endOfDayForDate:、残念ながらありません...
ジュリアンF.ウェイナート2016年

4

私にとっては、ここやstackoverflowのどこでうまくいったかという答えはありません。今日の始めに私はこれをしました。

NSCalendar * gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 
[gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];    
NSDateComponents *components = [gregorian components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:[NSDate date]]; 
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; 
NSDate *beginningOfToday = [gregorian dateFromComponents:components];

なお、この[gregorian setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

カレンダーが作成されると、現在のタイムゾーンで初期化され、コンポーネントから日付が抽出されると、NSDateにはタイムゾーンがないため、現在のタイムゾーンの日付はUTCタイムゾーンと見なされます。したがって、コンポーネントを抽出する前に、後でこれらのコンポーネントから日付を抽出するときに、タイムゾーンを設定する必要があります。


4

スウィフト3

  class func today() -> NSDate {
        return NSDate()
    }

    class func dayStart() -> NSDate {
          return NSCalendar.current.startOfDay(for: NSDate() as Date) as NSDate
    }

    class func dayEnd() -> NSDate {
        let components = NSDateComponents()
        components.day = 1
        components.second = -1
        return NSCalendar.current.date(byAdding: components as DateComponents, to: self.dayStart() as Date)
    }

4

* XCode8を使用したSwift3
AppleはNS、クラス名からを削除しているため、NSDateに交換できますDate。それらをキャストしようとすると、常に失敗するというコンパイラの警告が表示されることがありますが、プレイグラウンドで実行すると正常に機能します。

生成さNSDateれたコアデータモデルをに置き換えDateても動作します。

extension Date {
  func startTime() -> Date {
    return Calendar.current.startOfDay(for: self)
  }

  func endTime() -> Date {
    var components = DateComponents()
    components.day = 1
    components.second = -1
    return Calendar.current.date(byAdding: components, to: startTime())!
  }
}

4

Swift 3以降

extension Date {
    var startOfDayDate: Date {
        return Calendar.current.startOfDay(for: self)
    }

    var endOfDayDate: Date {
        let nextDayDate = Calendar.current.date(byAdding: .day, value: 1, to: self.startOfDayDate)!
        return nextDayDate.addingTimeInterval(-1)
    }
}

使用法:

var currentDayStart = Date().startOfDayDate
var currentDayEnd = Date().endOfDayDate

2

結果を取得するもう1つの方法:

NSDate *date = [NSDate date];

NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = [[NSCalendar currentCalendar] ordinalityOfUnit:(NSCalendarUnitDay) inUnit:(NSCalendarUnitEra) forDate:date];
NSDate *dayBegin = [[NSCalendar currentCalendar] dateFromComponents:components];

components.day += 1;
NSDate *dayEnd = [[NSCalendar currentCalendar] dateFromComponents:components];

2

NSDayCalendarUnitコンポーネントが不足しています。


2

Objective-C

NSCalendar * calendar = [NSCalendar currentCalendar];
NSDate * startDate = [calendar startOfDayForDate:[NSDate date]];
NSLog(@"start date is %@", startDate);

2

Swift 4の場合

    var calendar = Calendar.current
    calendar.timeZone = NSTimeZone(abbreviation: "UTC")! as TimeZone
    let dateAtMidnight = calendar.startOfDay(for: Date())

    //For End Date
    var components = DateComponents()
    components.day = 1
    components.second = -1

    let dateAtEnd = calendar.date(byAdding: components, to: dateAtMidnight)

    print("dateAtMidnight :: \(dateAtMidnight)")
    print("dateAtEnd :: \(dateAtEnd!)")

2

Swiftでこれを行う最も簡単な方法は次のとおりだと思います:

extension Date {
    func startOfDay() -> Date {
        return Calendar.current.startOfDay(for: self)
    }
    func endOfDay() -> Date {
        return Calendar.current.date(bySettingHour: 23, minute: 59, second 59, of: self)
    }
}

それは最高です!どうも!
Baran Emre

1

iOS 8.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+Foundationには組み込み関数があるので、そのまま使用できます。独自の機能を実装する必要はありません。

public func startOfDay(for date: Date) -> Date

したがって、次のように使用できます。

let midnightDate = Calendar(identifier: .gregorian).startOfDay(for: Date())

これはデバイスのタイムゾーンを考慮に入れることを覚えておく価値があります。たとえばUTCゾーンが必要な場合は.timeZone、オンに設定できcalendarます。

Appleのリファレンスページへのリンク:https : //developer.apple.com/reference/foundation/nscalendar/1417161-startofday


1

ちょうど別の方法で使用するdateInterval(of:start:interval:for:)Calendar

戻ったときstartDate、その日の始まりとその日intervalの秒数が含まれます。

func startAndEnd(of date : Date) -> (start : Date, end : Date) {
    var startDate = Date()
    var interval : TimeInterval = 0.0
    Calendar.current.dateInterval(of: .day, start: &startDate, interval: &interval, for: date)
    var endDate = startDate.addingTimeInterval(interval-1)
    return (start : startDate, end : endDate)
}

let (start, end) = startAndEnd(of: Date())
print(start, end)

1

これは私がSwift 4.2に使用するものです:

    let calendar = Calendar.current
    let fromDate = calendar.startOfDay(for: Date())
    let endDate = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: Date())

私にとっては魅力のように機能します。これをの開始日と終了日の拡張子に追加することもできますが、拡張子をDate追加すると、コンパイル時間が長くなるため(クラスと同じファイルでない限り)、1か所または1つのクラスでのみ必要な場合に注意してください。 ..拡張機能を使用しないでください。


0
extension Date {
    func stringFrom(dateFormat: String) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = dateFormat
        return formatter.string(from: self)
    }

    func firstSecondInDay() -> Date {
        let dayStr = self.stringFrom(dateFormat: "yyyy-MM-dd")
        let firstSecondStr = "\(dayStr) 00:00:00"
        let format = DateFormatter()
        format.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return format.date(from: firstSecondStr)!
    }

    func lastSecondInDay() -> Date {
        let dayStr = self.stringFrom(dateFormat: "yyyy-MM-dd")
        let laseSecondStr = "\(dayStr) 23:59:59"
        let format = DateFormatter()
        format.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return format.date(from: laseSecondStr)!
    }
}

0

参考までに、Swift 4一日の始まりと終わりを設定する簡単な方法は

var comp: DateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())
comp.hour = 0
comp.minute = 0
comp.second = 0
comp.timeZone = TimeZone(abbreviation: "UTC")!


//Set Start of Day
let startDate : Date = Calendar.current.date(from: comp)!
print(“Day of Start : \(startDate)")


//Set End of Day
comp.hour = 23
comp.minute = 59
comp.second = 59

let endDate : Date = Calendar.current.date(from:comp)!
print("Day of End : \(endDate)")

-1

カレンダーユニットは、間隔として考える必要があります。iOS 10の時点でこれにCalendarはいくつかの素晴らしい方法があります

let day = Calendar.autoupdatingCurrent.dateInterval(of: .day, for: Date())
day?.end
day?.start

同じ方法を使用して、任意のカレンダーコンポーネントの開始/終了(週/月/年など)を取得できます。


これは誤りです。day?.endは、今夜の11:59 PMではなく、明日の12:00 AMと評価されます。
Casey Wagner
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.