我有一个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 */
),因此您只能使用下列其中一项:
有没有办法同时设置小时,分钟和秒并保留日期(日/月/年)?
答案 0 :(得分:81)
您的陈述
上述方法的问题是你只能设置一个单位 时间......
不正确。 NSCalendarUnit
符合RawOptionSetType
协议
继承自BitwiseOperationsType
。这意味着选项可以是按位
结合&
和|
。
在 Swift 2(Xcode 7)中,这又被改变了
OptionSetType
提供类似集合的界面,请参阅
例如Error combining 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)
答案 1 :(得分:33)
是
您根本不需要操纵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())!
对于Swift 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
在OS X Mavericks(10.9)中引入了 dateBySettingHour
,并在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);
答案 2 :(得分:8)
以下是您如何使用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;
- )
答案 3 :(得分:5)
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,因为日期对象本身不保留或关心时区值。
小心!由于计算链中某处的时区偏移,结果值可能会有所不同!
答案 4 :(得分:2)
答案 5 :(得分:1)
在我看来,最容易验证的解决方案,但可能不是最快的,是使用字符串。
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)
}
答案 6 :(得分:0)
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!
}
答案 7 :(得分:0)
迅速5 +
let date = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())
答案 8 :(得分:0)
使用当前日历获取当前时间的一天的开始。
let today = Calendar.current.startOfDay(for: Date())