Issue on adding an event to iOS Calendar by comparing dates Swift 3 - nsdate

I've just updated one of my apps to Xcode 8 - Swift 3, and now I get a wired issue while trying to add an event that has a start and end date. Here's the code:
#IBAction func addToCalButt(_ sender: AnyObject) {
let eventStore = EKEventStore()
switch EKEventStore.authorizationStatus(for: EKEntityType.event) {
case .authorized: insertEvent(eventStore)
case .denied: print("Access denied")
case .notDetermined:
eventStore.requestAccess(to: .event, completion: { (granted, error) -> Void in
if granted { self.insertEvent(eventStore)
} else { print("Access denied") }
})
default: print("Case Default")
}
}
func insertEvent(_ store: EKEventStore) {
let calendars = store.calendars(for: EKEntityType.event)
for calendar in calendars {
if calendar.title == "Calendar" {
// Get Start and End dates
let startDate = eventObj[EVENTS_START_DATE] as! Date
let endDate = eventObj[EVENTS_END_DATE] as! Date
// Create Event
let event = EKEvent(eventStore: store)
event.title = "\(eventObj[EVENTS_TITLE]!)"
event.startDate = startDate
event.endDate = endDate
event.calendar = calendar
if startDate < endDate {
print("less")
} else {
print("more")
}
// Save Event in Calendar
do {
try store.save(event, span: .thisEvent)
simpleAlert("This Event has been added to your iOS Calendar")
} catch {
print("ERROR SAVING EVENT TO CAL: \(error)")
}
print("startDate: \(startDate) \endDate: \(endDate)")
}
}
}
and here's the console message:
more
ERROR SAVING EVENT TO CAL: Error Domain=EKErrorDomain Code=4 "The start date must be before the end date." UserInfo={NSLocalizedDescription=The start date must be before the end date.}
startDate: 2106-09-20 12:00:00 PM +0000
endDate: 2016-09-22 12:00:00 AM +0000
As you can see the start date is earlier than the end date, so I really can't understand what's wrong in there :(
Any help will be greatly appreciated.

As #Dustin Spengler says, the startDate has 2106 as year, while the endDate has 2016, so of course Xcode is right :)

Related

Date for titleForHeaderInSection with FetchedResultsController

I have a property #NSManaged public var sectionKeyDate: Date? I am trying to use for the sectionKey. I'm having an issue getting the resulting string from the NSFetchedResultsSectionInfo to format into a Date, to then be converted back into a formatted string.
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let sectionInfo = fetchedResultsController.sections?[section] else {
return nil
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-DD"
print("sectionInfo.name: ", sectionInfo.name)
print("Date: ", formatter.date(from: sectionInfo.name))
guard let date = formatter.date(from: sectionInfo.name) else { return "Error" }
let string = formatter.string(from: date)
return string
}
The conversion from a string to date is failing and return nil.
sectionInfo.name: 2021-03-25 05:00:00 +0000
Date: nil
(1) I'm not sure how to format this correctly.
(2) I'm not entirely sure if using a Date for the sectionKeyPath is an ok thing to do.
The issue was in getting the correct dateFormat.
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ssZ"
let date = formatter.date(from: sectionInfo.name)

Grouping FechedResults by Month/Year to display a swiftui list with sections

I have a core data entity (LogEntry) that includes a date attribute. I'm trying to migrate a view to SwiftUI and the view must show all the log entries grouped by Year Month (and sorted chronologically) like so:
JUN 2017
Log Entry 1 (June 10)
Log Entry 2 (June 16)
Log Entry 3 (June 17)
JUL 2017
Log Entry 1 (July 1)
Log Entry 2 (July 3)
etc.
I have been able to achieve the desired grouping with this code:
func group(_ result : FetchedResults<LogEntry>) -> [[LogEntry]] {
return Dictionary(grouping: result){ (element : LogEntry) in
sectionDateFormatter.string(from: element.date as Date)
}.values.map{$0}
}
var body: some View {
NavigationView {
List {
ForEach(group(logEntries), id: \.self) { (section: [LogEntry]) in //Works but not ordered
Section(header: Text( self.sectionDateFormatter.string(from: section[0].date as Date))) {
ForEach(section, id: \.self) { logEntry in
HStack {
Text("\(self.logDateFormatter.string(from: logEntry.date as Date))")
Spacer()
Text("\(logEntry.total) m").font(.subheadline)
}
}
}
}.id(logEntries.count)
}
.listStyle(PlainListStyle())
}
}
I have been trying to add the sorting for a while and I can't seem to find the right way to do it in the context of SwiftUI.
I tried this:
func update(_ result : FetchedResults<LogEntry>)-> [[LogEntry]]{
return Dictionary(grouping: result){ (element : LogEntry) in
sectionDateFormatter.string(from: element.date as Date)
}.values.sorted() { $0[0].date! < $1[0].date! }
}
... but I get a "Type of expression is ambiguous without more context" error and it fails to compile.
I also tried this:
func groupedByYearMonth(_ result: FetchedResults<LogEntry>) -> [Date: [LogEntry]] {
let empty: [Date: [LogEntry]] = [:]
return logEntries.reduce(into: empty) { acc, cur in
let components = Calendar.current.dateComponents([.year, .month], from: cur.date as Date)
let date = Calendar.current.date(from: components)!
let existing = acc[date] ?? []
acc[date] = existing + [cur]
}
}
... but in this case, I couldn't figure out how to tweak the SwiftUI list ForEach to work with it.
Any pointers would be greatly appreciated!
You can sort the the fetched results if you use a different key in the temporary dictionary that can be properly sorted. So for the DateFormatter used in the function I set the format to "yyyy-MM" instead.
Note that I start by sorting the input to the function but this step is not needed if the fetched result is already sorted on date which I recommend.
func group(_ result : FetchedResults<LogEntry>) -> [[LogEntry]] {
let sorted = result.sorted { $0.date < $1.date }
return Dictionary(grouping: sorted) { (element : LogEntry) in
dictionaryDateFormatter.string(from: element.date as Date)
}.sorted { $0.key < $1.key }.map(\.value)
}

How to remove motion time numbers of clock with String type in Swift?

I've code to show clock time with the timeLabel:UILabel in my app whit Swift3.
And that is:
override func viewWillAppear(_ animated: Bool) {
Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.currentTime), userInfo: nil, repeats: true)
}
func currentTime(){
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
if second % 2 == 0{
timeLabel.text = "\(hour):\(minutes)"
}else {
timeLabel.text = "\(hour) \(minutes)"
}
But when two points disappear between hour and minutes numbers, they are a little bit movement. How to fix that?
With a trick 😏 can be fix that.
By adding another label with same background color in else condition, Yup😉
For Swift 3:
var attributes = [String: AnyObject]()
attributes[NSForegroundColorAttributeName] = self.view.backgroundColor
let attributedString = NSAttributedString(string: ":", attributes: attributes)
label.attributedText = attributedString

How to overwrite strings within an if-loop in Swift

I have a few variables that I create within code for a view controller (basically, I'm just checking the values of segmented controls), but when I try to write into the string within the loops (shown below), nothing is written, and all strings remain "nil."
var textTypeVideo:String?
var textMultipleAgents:String?
var textAdditionalRooms:String?
var textMultipleVideos:String?
var textTurnaround:String?
Here are the functions that check to see where the segmented controls are:
#IBAction func typeOfVideoAction(sender: AnyObject) {
if typeOfVideoControl.selectedSegmentIndex == 0 {
textTypeVideo = "Standard Home Video"
} else {
textTypeVideo = "Standard CV Video"
}
}
#IBAction func mulitpleAgentScenesAction(sender: AnyObject) {
if multipleAgentScenesControl.selectedSegmentIndex == 0 {
textMultipleAgents = "Multiple Agent Scenes Desired"
} else {
textMultipleAgents = "No Multiple Agent Scenes"
}
}
#IBAction func additionalRoomsAction(sender: AnyObject) {
if additionalRoomsFeaturesControl.selectedSegmentIndex == 0 {
textAdditionalRooms = "Additional Rooms & Features Desired"
} else {
textAdditionalRooms = "No Additional Rooms & Features"
}
}
#IBAction func multipleVideosAction(sender: AnyObject) {
if multipleVideoCopiesControl.selectedSegmentIndex == 0 {
textMultipleVideos = "Second Video Copy Requested"
} else {
textMultipleVideos = "No Second Video Copy"
}
}
#IBAction func turnaroundAction(sender: AnyObject) {
if turnaroundControl.selectedSegmentIndex == 0 {
textTurnaround = "No Quick Turnaround"
} else if turnaroundControl.selectedSegmentIndex == 1 {
textTurnaround = "24 Hour Turnaround Desired"
} else if turnaroundControl.selectedSegmentIndex == 2 {
textTurnaround = "2 Business Day Turnaround Desired"
} else if turnaroundControl.selectedSegmentIndex == 3 {
textTurnaround = "3 Business Day Turnaround Desired"
} else {
textTurnaround = "5 Business Day Turnaround Desired"
}
}
Finally, this is what I want to fill in and print in an email:
let messageBody = "\(textTypeVideo) and \(textMultipleAgents) and \(textAdditionalRooms) and \(textMultipleVideos) and \(textTurnaround)"
mailComposerVC.setMessageBody(messageBody, isHTML: false)
Any help is greatly appreciated! I just can't seem to fill in the top variables with what they're supposed to be, based on the segmented controls! Thanks.

Dynamics CRM Script Help - Date Field Comparison to Current Date + Number Field

Order form has two fields, Ship Date (datefield) and Lead Time (number field in days).
When a ship date is entered, it should be greater than the current date + the lead time. alert user if not, and do not allow save of record.
There is one exception to the rule though: If the approved for rush field and approved by field is filled out the alert is not necessary and record can be saved.
++ It would be a plus if this could actually not account for weekend days. But not mandatory
function checkLeadTime
{
var shipDate = Xrm.Page.getAttribute("requestdeliveryby").getValue();
var leadTime = Xrm.Page.getAttribute("orbus_leadtime").getValue();
var leadTimeDate = Xrm.Page.getAttribute("orbus_leadtimedate").getValue():
if(leadTime != NULL)
{
var approvedRushProduction = xrm.getAttribute("orbus_projectapprovedrush").getValue();
var approvedBy = Xrm.Page.getAttribute("orbus_approvedbyid").getValue();
var currentTime = new Date();
var newDate = currentTime.setDays(currentTime.getDays + leadTime);
leadTimeDate.setValue(newDate);
if(approvedRushProduction == 0 && approvedBy == NULL)
{
if ( newDate < shipDate)
{
alert("Sorry, Ship Date is less than lead time!");
}
else
{
alert("Current Time = " + newDate);
}
}
}
}
You can attach your function to the form onSave event.
if ( newDate < shipDate ) {
alert("Sorry, Ship Date is less than lead time!");
Xrm.Page.context.getEventArgs().preventDefault();
} else {
alert("Current Time = " + newDate);
}
Use Xrm.Page.context.getEventArgs().preventDefault() to stop the save event.
To stop saving and show error message you can use:
Xrm.Page.getControl(fieldName).setNotification(message);
http://garethtuckercrm.com/2013/10/17/crm-2013-new-features-javascript-notifications/

Resources