NSCalendar.startOfDayForDate(date:) equivalent for iOS 7 with non-optional return type - swift

Is it possible to change an NSDate object so that the result is equivalent to NSCalendar.startOfDayForDate(date:)? That method is only available to iOS 8 and newer, but I am looking for something that works on iOS 7.
I have looked at two methods:
NSCalendar.dateFromComponents(comps:) as described here: NSDate beginning of day and end of day. For instance, like this:
class func startOfDay(date: NSDate, calendar: NSCalendar) -> NSDate {
if #available(iOS 8, *) {
return calendar.startOfDayForDate(date)
} else {
let dateComponents = calendar.components([.Year, .Month, .Day], fromDate: date)
return calendar.dateFromComponents(dateComponents)!
}
}
NSDateFormatter.dateFromString(string:) by way of
stringFromDate(date:), i.e. converting the NSDate object into a string without the time, then converting it back into an NSDate object.
The problem with both methods is that they return an optional NSDate. I am reluctant to unwrap this implicitly and I’d rather avoid changing the return type of the method within which these methods are called.

I think the calendar.components() method returns an optional, because you can theoretically enter components that do not create valid date, like 2000-02-30. If, as in your case, the components already come from a valid date, I would not be reluctant to implicitly unwrap the optional.

Related

How to fix the warning of type casting in 'if let' statement in Xcode 8.3?

Consider the following code:
let nsdate: NSDate? = NSDate()
if let date = nsdate as? Date { // a warning occurs here
print(date)
}
The compiler complains like this: Conditional downcast from 'NSDate?' to 'Date' is a bridging conversion; did you mean to use 'as'?
A cast from NSData to Data has the same problem. How to fix the it?
Try to cast to an optional Date:
if let date = nsdate as Date?
You're trying to optional cast of optional NSDate to NON optional Date. As long as NSDate is bridged from obj-c to Date, so this cast always success, so no optional cast required here, just basic cast as is enough. Then you need to cast optional value, so the resulting value has to be optional too, therefore Date? is appropriate here.
Swift 3.1 distinguishes
An optional down cast as? Foo
It casts a more unspecific to a more specific type for example
let dict : [String:Any] = ["Foo" : 12]
let number = dict["Foo"] as? Int
A bridge cast of an optional type as Foo?
It bridges a (Core)Foundation type to a toll free Swift type and vice versa.
It's the optional equivalent of the usual non-optional syntax
let string : NSString = "Foo"
let swiftString = string as String
The difference is subtle for the developer but very useful for the compiler.
Basically don't use the NS... Foundation classes in Swift 3 if there is a native Swift counterpart.
Try this:
let nsdate: NSDate? = NSDate()
if let date = nsdate {
print(date)
}
The compiler knows it´s an NSDate if unwrapped, so what you are doing is actually casting an NSDate to a Date

Why is `as Date` required for `timeIntervalSince()` with two `NSDate` objects?

I have an NSManagedObject object with:
#NSManaged public var timestamp: NSDate
I needed the time interval between two of these, so I implemented:
let interval = next.timestamp.timeIntervalSince(current.timestamp)
Why does this result in the following error?
'NSDate' is not implicitly convertible to 'Date'; did you mean to use
'as' to explicitly convert?
I'm surprised because both next and current are of type NSDate, and timeIntervalSince() is an NSDate method.
It's easily fixed by following the suggestion in the error, but I'd like to understand what going on here:
let interval = next.timestamp.timeIntervalSince(current.timestamp as Date)
In case it matters, this is on Swift 3.0.
Referring to NSDate Apple Documentation:
The Swift overlay to the Foundation framework provides the Date
structure, which bridges to the NSDate class. The Date value type
offers the same functionality as the NSDate reference type, and the
two can be used interchangeably in Swift code that interacts with
Objective-C APIs. This behavior is similar to how Swift bridges
standard string, numeric, and collection types to their corresponding
Foundation classes.
If you check timeIntervalSince method signature, it is func timeIntervalSince(_ anotherDate: Date) -> TimeInterval, note that anotherDate date type is Date (not NSDate anymore).
For more information about new value types, check this proposal of mutability and foundation value types, there is a bunch of new value types such as: NSData, NSMutableData -> Data, NSIndexPath -> IndexPath, NSNotification -> Notification...

Getting the current time as a decimal point number

I want to be able to get the current time as a decimal point number so it can be used. so for example if the time is 13:46 I want to get it as 13.46
It seems simple but I am struggling getting to it.
We can use an NSDateFormatter to do exactly this:
extension NSDate {
func currentTime() -> String {
let formatter = NSDateFormatter()
formatter.dateFormat = "HH.mm"
return formatter.stringFromDate(self)
}
}
And now we just use it by calling it on any instance of NSDate:
let now = NSDate()
print(now.currentTime())
you can stringify the time and serch lastindexOf(":") and substitue it with a "."
UPDATE
I don't really catch what program language are you using, but it's plenty of library for stringify object so if you have a 13:46 you can convert it to String and, in the same string library you could find the method lastIndexOf(char). But if you don't find it you can always write following this concepts:
String are an array of Char so you can cycle it and convert the char in that position in the char you need.

Using customized setter/getter and initializing the property for a swift date

I have a class called Trip which has an NSDate property called date. My desire is to make sure that the date property always has the time value set to the beginning of the day. I do this by:
Creating an NSCalendar constant called calendar so that I can use the startOfDayForDate method to reset the date value.
Creating a custom setter method for the date property that calls the startOfDayForDate method.
However, I want to initialize the date property to the start of today's date.
The code that I have so far is shown below.
class Trip {
private let calendar: NSCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
var date: NSDate {
get {
return self.date
}
set {
self.date = calendar.startOfDayForDate(newValue)
}
}
}
This code a) doesn't initialize the date property and b) (I discovered) results in an infinite loop when the setter is called. Upon further research, I believe that customized getters/setters are strictly computed, right?
How do I accomplish what I mentioned earlier:
a.) making sure that sets to the date property reset to the start of the day and
b.) initializing the date property to the start of today's date?
I think you want to have a date that will always be the start of the date. Replace your current date variable with this:
private var privateDate = NSDate()
var date: NSDate {
get {
return privateDate
}
set {
privateDate = calendar.startOfDayForDate(newValue)
}
}
There may be a slightly better way to do this, but I'm guessing your application won't have tens of thousands of your Trip class, so you should be fine.

Swift: Why class method has return type AnyObject?

NSDate.distantFuture() is documented to return an object of type NSDate.
So then, why does it have a return type of AnyObject, instead of NSDate?
In Objective-C distantFuture returns an id, not NSDate. Automatic Swift conversion makes this an AnyObject. When the class will be reviewed by Apple they will probably switch that to NSDate.
NSDate's distantFuture is actually from the distant past (at least Mac OS X 10.0, probably even before that). At this time many factory methods returned id because there was no instancetype. It was just to make it easier to call a subclasses method on the returned object.
This is actually documented as returning AnyObject.
returns nil if an event specified in the event mask does not happen before the specified date.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/#//apple_ref/occ/clm/NSDate/distantFuture**
distantFuture
Creates and returns an NSDate object representing a date in the distant future.
Declaration
SWIFT
class func distantFuture() -> AnyObject
OBJECTIVE-C
+ (id)distantFuture
Return Value
An NSDate object representing a date in the distant future (in terms of centuries).
Discussion
You can pass this value when an NSDate object is required to have the date argument essentially ignored. For example, the NSWindow method nextEventMatchingMask:untilDate:inMode:dequeue: returns nil if an event specified in the event mask does not happen before the specified date. You can use the object returned by distantFuture as the date argument to wait indefinitely for the event to occur.
myEvent = [myWindow nextEventMatchingMask:myEventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
Import Statement
import Foundation
Availability
Available in OS X v10.0 and later.