Updating NSCalendar to Swift3 - swift3

The following code, in Swift 1, throws the error: Cannot call value of non-function type 'Calendar'
class CyclicDay {
lazy var baseline: NSDate? = {
var components = NSDateComponents()
components.day = 02
components.month = 05
components.year = 2018
return NSCalendar.currentCalendar.datefromComponents(components)
}()
}
What are the Swift 3 equivalents of the NSDate and NSCalendar functions?

The equivalents of NSDate, NSDateComponents & NSCalendar for Swift 3 are:
Date
DateComponents
Calendar
Actually every (NS)Type has equivalent Type in Swift 3.
Now in Swift 3, your code will look like this:
class CyclicDay {
lazy var baseline: Date? = {
var components = DateComponents()
components.day = 02
components.month = 05
components.year = 2018
return Calendar.current.date(from: components)
}()
}

Related

SwiftUI display yesterday's date

How do I list yesterday's date in SwiftUI? It probably is a simple answer but I'm just learning to code and for some reason I can't seem to find the solution anywhere. Is it because it is too easy?
struct DateShown: View {
let datechoice: Datechoice
var body: some View {
Text(currentDate(date: Date()))
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.blue)
}
func currentDate(date: Date!) -> String {
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = "MMMM d, yyyy"
return date == nil ? "" : formatter.string(from: date)
}
}
I would rather use View extensions, though you also need Date formatting so I went the easier way and extended your solution. If the number at line "dayComponent.day" is positive, you go futher in time. I tested under:
swift 5
xcode 11.3.1
iOS 13.3.1 non beta
func yesterDay() -> String {
var dayComponent = DateComponents()
dayComponent.day = -1
let calendar = Calendar.current
let nextDay = calendar.date(byAdding: dayComponent, to: Date())!
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = "MMMM d, yyyy"
return formatter.string(from: nextDay). //Output is "March 6, 2020
}
Usage is the same as yours:
Text(yesterDay())

Finding Time bug in Swift 3.0

After converting my code to Swift 3.0, I have just one error left, saying that 'dateComponents' produces 'DateComponents', not the expected conextual result type 'NSDate?' I'll add a * on the line that error applies to. The * is not in the actual code.
I did not understand the code before hand, as it was written by a person I am no longer in touch with. The code sets a starting date for a timetabling app I wrote.
My code:
#IBOutlet weak var llllll: UILabel!
class CyclicDay {
enum CyclicDayError: Error {
case invalidStartDate }
lazy var baseline: NSDate? = {
var components = DateComponents()
components.day = 2
components.month = 5
components.year = 2016
* return NSCalendar.current.dateComponents(components) }()
func dayOfCycle(_ testDate: NSDate) throws -> Int {
if let start = baseline {
let interval = testDate.timeIntervalSince(start as Date)
let days = interval / (60 * 60 * 24)
return Int(days.truncatingRemainder(dividingBy: 14)) + 1 }
throw CyclicDayError.invalidStartDate }}
A couple of issues:
In Swift 3, you should use Calendar and Date rather than NSCalendar and NSDate.
The method to get the Date object from a DateComponents is date(from:). The dateComponents method is for going the other direction, to determine the DateComponents from a Date.
Thus:
lazy var baseline: Date? = {
var components = DateComponents()
components.day = 2
components.month = 5
components.year = 2016
return Calendar.current.date(from: components)
}()
Or
lazy var baseline: Date = {
var components = DateComponents()
components.day = 2
components.month = 5
components.year = 2016
return Calendar.current.date(from: components)!
}()
Try using Calendar and Date rather than NSCalendar or NSDate. It may solve the problem. Most of 'NS' prefix are abondoned in swift 3.0
First of all, why is baseline optional? The date 2016/5/2 doubtless exists.
The Swift 3 equivalent is simply
lazy var baseline: Date = {
let components = DateComponents(year:2016, month:5, day:2)
return Calendar.current.date(from:components)!
}()

Unexpectedly found nil while unwrapping an Optional value in Swift 3

I have a timetable app, and after converting everything to Swift 3, one particular line threw an EXC_BAD_INSTRUCTION error, stating "Unexpectedly found nil while unwrapping an Optional value"
Here is the code, the final line returns the error:
class CyclicDay {
enum CyclicDayError: Error {
case invalidStartDate }
lazy var baseline: Date! = {
var components = DateComponents()
components.day = 27
components.month = 3
components.year = 2017
return Calendar.current.date(from: components)!
}()
func dayOfCycle(_ testDate: Date) throws -> Int {
if let start = baseline {
let interval = testDate.timeIntervalSince(start as Date)
let days = interval / (60 * 60 * 24)
return Int(days.truncatingRemainder(dividingBy: 14)) + 1 }
throw CyclicDayError.invalidStartDate }}
override func viewDidLoad() {
// Do any additional setup after loading the view, typically from a nib.
let cd = CyclicDay()
let day = try! cd.dayOfCycle(Date())
let date = Date()
let calendar = Calendar.current
let components = calendar.dateComponents([.hour, .minute], from: date)
let hour = components.hour
let minutes = components.minute
_ = "\(String(describing: hour)):\(String(describing: minutes))"
let lengthTestHour = "\(String(describing: hour))"
let lengthTestMinute = "\(String(describing: minutes))"
let formatter = DateFormatter()
formatter.dateFormat = "a"
formatter.amSymbol = "AM"
formatter.pmSymbol = "PM"
let dateString = formatter.string(from: Date())
var finalHour = String()
if lengthTestHour.characters.count == 1 {
finalHour = String("0\(String(describing: hour))")
} else {
finalHour = "\(String(describing: hour))"
}
if lengthTestMinute.characters.count == 1 {
_ = "0\(String(describing: minutes))"
} else {_ = minutes }
let convert = finalHour
let mTime = Int(convert)
// mTime * 100 + minutes
let compTime = mTime! * 100 + minutes!
In Swift 3 all date components are optional, you need to unwrap the optionals
let hour = components.hour!
let minutes = components.minute!
otherwise you get in trouble with the string interpolations.
Btw: You don't need String(describing just write for example
_ = "\(hour):\(minutes)"
I'm wondering anyway why you do all the formatting stuff manually instead of using the date formatter you created.
The problem lies in these two lines:
let lengthTestHour = "\(String(describing: hour))"
let lengthTestMinute = "\(String(describing: minutes))"
You thought lengthTestHour will store a value like "7" and lengthTestMinute will have a value like "33". But no, lengthTestHours actually holds "Optional(7)" and lengthTestMinutes actually holds "Optional(33)".
You then assign lengthTestHour to convert and try to convert that Optional(7) thing into an Int, which obviously can't be done. Now mTime is nil and you try to force unwrap in the last line. BOOM!
This is because String(describing:) returns an optional. The two lines can be shortened and fixed by doing:
let lengthTestHour = "\(hour!)"
let lengthTestMinute = "\(minute!)"

FSCalendar events in Swift 3

How can events be added to an FSCalendar in swift 3?
Implement the appropriate methods in a class adopting FSCalendarDataSource.
var datesWithEvent = ["2015-10-03", "2015-10-06", "2015-10-12", "2015-10-25"]
var datesWithMultipleEvents = ["2015-10-08", "2015-10-16", "2015-10-20", "2015-10-28"]
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
if self.datesWithEvent.contains(dateString) {
return 1
}
if self.datesWithMultipleEvents.contains(dateString) {
return 3
}
return 0
}
Based On FsCalendar Documentation

Swift 3: Internal Extension to Set Time

I had this internal Date extension that appears to no longer work in Swift 3:
internal extension DateComponents {
func to12pm() {
self.hour = 12
self.minute = 0
self.second = 0
}
}
The error message is:
Cannot assign to property: 'self' is immutable
How do I achieve this in Swift 3?
Additional Info (if needed): It was called by this Date extension:
func endOfWeek(_ weekday: Int) -> Date? {
guard
let cal = Calendar.current,
var comp: DateComponents = (cal as Calendar).components([.weekOfYear], from: self)
else {
return nil
}
comp.weekOfYear = 1
comp.day -= 1
comp.to12pm()
return (cal as NSCalendar).date(byAdding: comp, to: self.startOfWeek(weekday)!, options: [])!
}
Which now looks like this in Swift 3:
func endOfWeek(_ weekday: Int) -> Date? {
let cal = Calendar.current
var comp = cal.dateComponents([.weekOfYear], from: self)
comp.weekOfYear = 1
comp.day? -= 1
//This does not have the "comp.to12pm()" that the Swift 2 version did
return cal.date(byAdding: comp, to: self.startOfWeek(weekday)!)!
}
DateComponents is now a struct thats why it is throwing that error:
Cannot assign to property: 'self' is immutable
You need to create a new var from self, change it and return it as follow:
extension DateComponents {
var to12pm: DateComponents {
var components = self
components.hour = 12
components.minute = 0
components.second = 0
components.nanosecond = 0
return components
}
}