ios 如何将 NSDate 对象设置为午夜?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26189656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I set an NSDate object to midnight?
提问by AstroCB
I have an NSDate
object and I want to set it to an arbitrary time (say, midnight) so that I can use the timeIntervalSince1970
function to retrieve data consistently without worrying about the time whenthe object is created.
我有一个NSDate
对象,我想将它设置为任意时间(比如半夜),这样我可以使用timeIntervalSince1970
的功能一致,而不用担心时间来检索数据时创建的对象。
I've tried using an NSCalendar
and modifying its components by using some Objective-C methods, like this:
我已经尝试使用 anNSCalendar
并使用一些 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)
The problem with the above method is that you can only set one unit of time (/* a unit of time */
), so you could only have one of the following be accurate:
上述方法的问题是你只能设置一个时间单位(/* a unit of time */
),所以你只能有以下一种是准确的:
- Day
- Month
- Year
- Hours
- Minutes
- Seconds
- 日
- 月
- 年
- 小时
- 分钟
- 秒
Is there a way to set hours, minutes, and seconds at the same time and retain the date (day/month/year)?
有没有办法同时设置小时、分钟和秒并保留日期(日/月/年)?
回答by Martin R
Your statement
你的陈述
The problem with the above method is that you can only set one unit of time ...
上述方法的问题是你只能设置一个时间单位......
is not correct. NSCalendarUnit
conforms to the RawOptionSetType
protocol which
inherits from BitwiseOperationsType
. This means that the options can be bitwise
combined with &
and |
.
是不正确的。NSCalendarUnit
符合RawOptionSetType
继承自的协议BitwiseOperationsType
。这意味着这些选项可以与&
和按位组合|
。
In Swift 2 (Xcode 7)this was changed again to be
an OptionSetType
which offers a set-like interface, see
for example Error combining NSCalendarUnit with OR (pipe) in Swift 2.0.
在Swift 2 (Xcode 7) 中,这再次更改为OptionSetType
提供类似集合的界面,例如在 Swift 2.0 中将 NSCalendarUnit 与 OR (pipe) 组合在一起的错误。
Therefore the following compiles and works in iOS 7 and iOS 8:
因此,以下内容可在 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)
(Note that I have omitted the type annotations for the variables, the Swift compiler infers the type automatically from the expression on the right hand side of the assignments.)
(请注意,我省略了变量的类型注释,Swift 编译器会根据赋值语句右侧的表达式自动推断类型。)
Determining the start of the given day (midnight) can also done
with the rangeOfUnit()
method (iOS 7 and iOS 8):
也可以使用以下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)
Ifyour deployment target is iOS 8 then it is even simpler:
如果您的部署目标是 iOS 8,那么它就更简单了:
let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let newDate = cal.startOfDayForDate(date)
Update for Swift 3 (Xcode 8):
Swift 3 (Xcode 8) 的更新:
let date = Date()
let cal = Calendar(identifier: .gregorian)
let newDate = cal.startOfDay(for: date)
回答by AstroCB
Yes.
是的。
You don't need to fiddle with the components of the NSCalendar
at all; you can simply call the dateBySettingHour
method and use the ofDate
parameter with your existing 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())!
For Swift 3:
对于 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)!
Then, to get your time since 1970, you can just do
然后,为了获得自 1970 年以来的时间,你可以这样做
let time: NSTimeInterval = newDate.timeIntervalSince1970
dateBySettingHour
was introduced in OS X Mavericks (10.9) and gained iOS support with iOS 8.
dateBySettingHour
是在 OS X Mavericks (10.9) 中引入的,并在 iOS 8 中获得了 iOS 支持。
Declaration in NSCalendar.h
:
声明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);
回答by Mike Gledhill
Here's an example of how you would do it, without using the dateBySettingHour
function (to make sure your code is still compatible with iOS 7 devices):
下面是一个示例,说明如何在不使用该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];
Yuck.
哎呀。
There is a reason why I prefer coding in C#...
我更喜欢用 C# 编码是有原因的...
Anyone fancy some readable code..?
任何人都喜欢一些可读的代码..?
DateTime midnightLastNight = DateTime.Today;
;-)
;-)
回答by t1ser
SwiftiOS 8 and up: People tend to forget that the Calendar and DateFormatter objects have a TimeZone. If you do not set the desired timzone and the default timezone value is not ok for you, then the resulting hours and minutes could be off.
Swift iOS 8 及更高版本:人们往往会忘记 Calendar 和 DateFormatter 对象有一个 TimeZone。如果您没有设置所需的时区并且默认时区值不适合您,那么由此产生的小时和分钟可能会关闭。
Note:In a real app you could optimize this code some more.
注意:在实际应用中,您可以进一步优化此代码。
Note:When not caring about timezones, the results could be OK on one device, and bad on an other device just because of different timezone settings.
注意:当不关心时区时,结果可能在一台设备上正常,而在另一台设备上可能只是因为时区设置不同。
Note:Be sure to add an existing timezone identifier! This code does not handle a missing or misspelled timezone name.
注意:一定要添加一个现有的时区标识符!此代码不处理丢失或拼写错误的时区名称。
func dateTodayZeroHour() -> Date {
var cal = Calendar.current
cal.timeZone = TimeZone(identifier: "Europe/Paris")!
return cal.startOfDay(for: Date())
}
You could even extend the language. If the default timezone is fine for you, do not set it.
你甚至可以扩展语言。如果默认时区适合您,请不要设置它。
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)!
}
}
And use it like this:
并像这样使用它:
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)")
The string conversions and the DateFormatter are needed in our case for some formatting and to move the timezone since the date object in itself does not keep or care about a timezone value.
在我们的例子中需要字符串转换和 DateFormatter 来进行一些格式化和移动时区,因为日期对象本身并不保留或关心时区值。
Watch out!The resulting value could differ because of a timezone offset somewhere in your calculating chain!
小心!由于计算链中某处的时区偏移,结果值可能会有所不同!
回答by Francois Nadeau
回答by Jason
In my opinion, the solution, which is easiest to verify, but perhaps not the quickest, is to use strings.
在我看来,最容易验证但可能不是最快的解决方案是使用字符串。
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)
}
回答by William Hu
Swift 5+
斯威夫特 5+
let date = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())
回答by Frank Hou
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!
}