簡體   English   中英

如何將 NSDate 對象設置為午夜?

[英]How can I set an NSDate object to midnight?

我有一個NSDate對象,我想將其設置為任意時間(例如午夜),以便我可以使用timeIntervalSince1970函數一致地檢索數據,而不必擔心創建對象的時間。

我嘗試使用NSCalendar並使用一些 Objective-C 方法修改其組件,如下所示:

let date: NSDate = NSDate()
let cal: NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)!

let components: NSDateComponents = cal.components(NSCalendarUnit./* a unit of time */CalendarUnit, fromDate: date)
let newDate: NSDate = cal.dateFromComponents(components)

上述方法的問題是你只能設置一個時間單位( /* a unit of time */ ),所以你只能有以下之一是准確的:

  1. 小時
  2. 分鍾

有沒有辦法同時設置小時、分鍾和秒並保留日期(日/月/年)?

你的陳述

上述方法的問題是只能設置一個單位時間...

是不正確的。 NSCalendarUnit符合從BitwiseOperationsType繼承的RawOptionSetType協議。 這意味着選項可以按位與&|組合。 .

Swift 2 (Xcode 7)中,它再次被更改為提供類似集合的接口的OptionSetType ,例如,參見Error combine NSCalendarUnit with OR (pipe) in Swift 2.0

因此,以下在 iOS 7 和 iOS 8 中編譯和工作:

let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!

// Swift 1.2:
let components = cal.components(.CalendarUnitDay | .CalendarUnitMonth | .CalendarUnitYear, fromDate: date)
// Swift 2:
let components = cal.components([.Day , .Month, .Year ], fromDate: date)

let newDate = cal.dateFromComponents(components)

(請注意,我省略了變量的類型注釋,Swift 編譯器會自動從賦值右側的表達式中推斷出類型。)

還可以使用rangeOfUnit()方法(iOS 7 和 iOS 8)確定給定一天(午夜)的開始:

let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
var newDate : NSDate?

// Swift 1.2:
cal.rangeOfUnit(.CalendarUnitDay, startDate: &newDate, interval: nil, forDate: date)
// Swift 2:
cal.rangeOfUnit(.Day, startDate: &newDate, interval: nil, forDate: date)

如果您的部署目標是 iOS 8,那么它就更簡單了:

let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let newDate = cal.startOfDayForDate(date)

Swift 3 (Xcode 8) 的更新:

let date = Date()
let cal = Calendar(identifier: .gregorian)
let newDate = cal.startOfDay(for: date)

是的。

您根本不需要擺弄NSCalendar的組件; 您可以簡單地調用dateBySettingHour方法並將ofDate參數與您現有的日期一起使用。

let date: NSDate = NSDate()
let cal: NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)!

let newDate: NSDate = cal.dateBySettingHour(0, minute: 0, second: 0, ofDate: date, options: NSCalendarOptions())!

對於斯威夫特 3:

let date: Date = Date()
let cal: Calendar = Calendar(identifier: .gregorian)

let newDate: Date = cal.date(bySettingHour: 0, minute: 0, second: 0, of: date)!

然后,為了讓你的時間從 1970 年開始,你可以做

let time: NSTimeInterval = newDate.timeIntervalSince1970

dateBySettingHour在 OS X Mavericks (10.9) 中引入,並在 iOS 8 中獲得了 iOS 支持。

NSCalendar.h中的聲明:

/*
    This API returns a new NSDate object representing the date calculated by setting hour, minute, and second to a given time.
    If no such time exists, the next available time is returned (which could, for example, be in a different day than the nominal target date).
    The intent is to return a date on the same day as the original date argument.  This may result in a date which is earlier than the given date, of course.
 */
- (NSDate *)dateBySettingHour:(NSInteger)h minute:(NSInteger)m second:(NSInteger)s ofDate:(NSDate *)date options:(NSCalendarOptions)opts NS_AVAILABLE(10_9, 8_0);

這是一個不使用dateBySettingHour函數的示例(以確保您的代碼仍然與 iOS 7 設備兼容):

NSDate* now = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
NSDate* midnightLastNight = [gregorian dateFromComponents:dateComponents];

呸。

我喜歡用 C# 編碼是有原因的...

任何人都喜歡一些可讀的代碼..?

DateTime midnightLastNight = DateTime.Today;

;-)

Swift iOS 8 及更高版本:人們往往會忘記 Calendar 和 DateFormatter 對象有一個 TimeZone。 如果您沒有設置所需的時區,並且默認時區值不適合您,則生成的小時和分鍾可能會關閉。

注意:在實際應用中,您可以進一步優化此代碼。

注意:當不關心時區時,結果在一台設備上可能是好的,而在另一台設備上的結果可能會因為時區設置不同而變差。

注意:一定要添加一個現有的時區標識符! 此代碼不處理丟失或拼寫錯誤的時區名稱。

func dateTodayZeroHour() -> Date {
    var cal = Calendar.current
    cal.timeZone = TimeZone(identifier: "Europe/Paris")!
    return cal.startOfDay(for: Date())   
}

你甚至可以擴展語言。 如果默認時區適合您,請不要設置它。

extension Date {
    var midnight: Date {
        var cal = Calendar.current
        cal.timeZone = TimeZone(identifier: "Europe/Paris")!
        return cal.startOfDay(for: self)
    }
    var midday: Date {
        var cal = Calendar.current
        cal.timeZone = TimeZone(identifier: "Europe/Paris")!
        return cal.date(byAdding: .hour, value: 12, to: self.midnight)!
    }
}

並像這樣使用它:

let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "Europe/Paris")
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"

let midnight = Date().midnight
let midnightString = formatter.string(from: midnight)
let midday = Date().midday
let middayString = formatter.string(from: midday)

let wheneverMidnight = formatter.date(from: "2018/12/05 08:08:08")!.midnight
let wheneverMidnightString = formatter.string(from: wheneverMidnight)

print("dates: \(midnightString) \(middayString) \(wheneverMidnightString)")

在我們的例子中,字符串轉換和 DateFormatter 需要用於某些格式化和移動時區,因為日期對象本身並不保留或關心時區值。

小心! 結果值可能會因計算鏈中某處的時區偏移而有所不同!

斯威夫特 5+

let date = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())

以防萬一有人正在尋找這個:

使用SwiftDate你可以這樣做:

Date().atTime(hour: 0, minute: 0, second: 0)

在我看來,最容易驗證但可能不是最快的解決方案是使用字符串。

func set( hours: Int, minutes: Int, seconds: Int, ofDate date: Date ) -> Date {

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"

    let newDateString = "\(dateFormatter.string(from: date)) \(hours):\(minutes):\(seconds)"

    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

    return dateFormatter.date(from: newDateString)
}
func resetHourMinuteSecond(date: NSDate, hour: Int, minute: Int, second: Int) -> NSDate{
    let nsdate = NSCalendar.currentCalendar().dateBySettingHour(hour, minute: minute, second: second, ofDate: date, options: NSCalendarOptions(rawValue: 0))
    return nsdate!
}

使用當前日歷獲取當前時間的一天開始。

let today = Calendar.current.startOfDay(for: Date())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM