Inserting into Array and comparing Dates Swift iOS Code - ios

I am attempting to create an array that will store 365 integers, it must be filled completely. I am using Healthkit to figure out the users steps from a year back, hence the array size. Every integer represents 1 day.
I have done this in android already and it worked perfectly, I got 365 integers back with 0's for the days with no steps, however, the problem is with iOS health kit I get nothing from days with no data, which I need. In order to do this I thought I would compare the date variable I get with the date of the current day + 1 and loop through the array to see if it find any matching cases, if not put a 0 into it at the end.
So in order to do this I created an array of 365, at the line var ID = 0 is where I attempt to store the integers correctly into the array. I am using Swift 4.
struct stepy {
static var step = [365]
}
This is where I enumerate through the stepData, first at var ID I attempt to compare the date I get in the enumerate loop with the current date (basically index 0 in the array, which represents the first day, the current day).
However I got a problem, currently I believe I would overwrite the days which already has been inputted into the date at the second step enumeration? Also I can't get the date code to compile properly, I just get the Date has no valid member called "add"
stepsQuery.initialResultsHandler = { query, results, error in
let endDate = NSDate()
let startDate = calendar.date(byAdding: .day, value: -365, to: endDate as Date, wrappingComponents: false)
if let myResults = results{
myResults.enumerateStatistics(from: startDate!, to: endDate as Date) { statistics, stop in
if let quantity = statistics.sumQuantity(){
var date = statistics.startDate
let steps = quantity.doubleValue(for: HKUnit.count())
var id = 0
var dateToInsert = date
var today = Date()
var todaytwo = Date()
for index in 0..<stepy.step.count {
if dateToInsert != today {
id = index + 1
today.(Calendar.current.date(byAdding: .day, value: -1, to: today)
stepy.step.append(0)
}
if date == dateToInsert as Date {
today.add(Calendar.current.date(byAdding: .day, value: -1, to: today)
stepy.step.append(Int(steps))
id = index + 1
}
}
}
}
}
}

static var step = [365]
The above doesn't make sense. It does not create an array of 365 integers, it creates an array with one integer in it that is 365. What you need is
static var step: [Int] = []
which creates an empty array you can just append your results to
currently I believe I would overwrite the days which already has been inputted into the date at the second step enumeration?
because your code appends to the array, which is the same as in Java: myArrayList.add(element), this is not a problem.
Also I can't get the date code to compile properly, I just get the Date has no valid member called "add"
Correct, it doesn't. Also this line:
today.(Calendar.current.date(byAdding: .day, value: -1, to: today)
does not make any sense. That should be causing a compiler error to.
Anyway, I don't see what the point of all that is. Your outer loop presumably loops through the statistics, one per day, so just do your calculation and append to the array. It'll be oldest first, but you can then just reverse the array to get newest first.

Related

Sort received dates from response in swift

I am working on code where I am receiving lots of data associated with dates
each object having one date parameter and there might many objects with the same date.
I need to show this all objects in UITableView. each object as one cell.
I succeed in that,
I need to get unique dates from the response array of objects.
Those unique dates will be stored in an array which will act as a number of sections of my table view with section header title will be the date from the unique date array.
somehow I am able to sort out that with what I want,
The only problem I am facing is I am not able to sort the unique date array
every time the sequence change.
I need the latest date as the first date and the oldest date as the end date.
How to achieve this in swift.
Following is a piece of code I have written
let sortedKeys = Array(dictValue.keys).sorted(by: {$0 > $1})
print(sortedKeys)
here dicValue.keys is my unique date array and I wanted to sort it.
Following is a sample response I am getting
["08/03/2021”, “10/02/2021”, "26/04/2021", "25/03/2021”, "09/12/2020”, , "27/04/2021”, "23/03/2021”, "11/01/2021”, "05/03/2021”, "09/03/2021”, "16/10/2020", "19/03/2021", "12/10/2020" ]
and after applying sort I am getting the following output
[“27/04/2021", "26/04/2021", "25/03/2021", "23/03/2021", "19/03/2021", "16/10/2020", "12/10/2020", "11/01/2021", "10/02/2021", "09/12/2020", "09/03/2021", "08/03/2021", "05/03/2021”]
where dates are not properly sorted out.
Can anyone please help me out with it.
Thanks in advance.
This string date format is inappropriate for sorting, because the most significant component is day. Only a date format like yyyy/MM/dd can be sorted properly by comparison operator >.
However this is Swift. The closure can contain anything as long as it returns a Bool. You could sort the array with a custom sort algorithm. It splits the strings into components and sorts first year then month then day
let sortedKeys = dictValue.keys.sorted { (date1, date2) -> Bool in
let comps1 = date1.components(separatedBy: "/")
let comps2 = date2.components(separatedBy: "/")
return (comps1[2], comps1[1], comps1[0]) > (comps2[2], comps2[1], comps2[0])
}
print(sortedKeys)
If you want to sort a date, just sort a Date. Date supports Hashable and can be used as a dictionary key, you could map your original dictionary and by using a DateFormatter to format your string keys into Dates then you can easily sort them.
let dictionary = ["08/03/2021": 2, "10/02/2021": 5, "26/04/2021" : 6]
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy" // You should probably adjust other properties of the formatter
let newDict = Dictionary(uniqueKeysWithValues:
dictionary.map { (key, value) -> (Date, Int) in
print("Key: \(key)")
return (formatter.date(from: key)!, value)
})
let sortedDates = newDict.keys.sorted { $0 > $1 }
let value = newDict[sortedDates[0]]

Get row where certain date value occurs

I would like to persist the last row with yesterday's date.
My data looks like the following:
I have tried the following to persist the data, which works well.
function moveValuesOnly() {
var ss = SpreadsheetApp.getActive().getSheetByName('Store values');
Logger.log(ss.getName());
// get yesterday's date
var now = new Date();
var yesterday = new Date();
yesterday.setDate(now.getDate()-1);
yesterday = Utilities.formatDate(yesterday, "GMT+1", 'yyyy-MM-dd');
Logger.log("yesterday: " + yesterday);
var source = ss.getRange('4:4');
source.copyTo(ss.getRange('4:4'), {contentsOnly: true});
source.setFontWeight("bold");
}
Find below an example spreadsheet:
Sample Spreadsheet
As you can see I am getting yesterday's date correctly formatted in my script as in my Date column. I also can correctly 'persist' the data.
My problem is that I do not know how to get the range where yesterday's date occurs so that I can hand it over in my script to persist it.
Any suggestions how to get the row that matches yesterday's date.
not totally sure what you mean by "persist" but the function below returns the row number for the first row with yesterday's date in it:
function getYesterdayRow(yesterdayDate,columnRange) {
var displayValues = columnRange.getDisplayValues();
for (var i = 0; i < displayValues.length; i++) {
var displayValue = displayValues[i][0];
if (displayValue === yesterdayDate) return i + 1;
}
return 0;
}
You can call it like this in your code after you've defined yesterday:
var yesterdayRow = getYesterdayRow(yesterday,ss.getRange(A:A))
Note that this function quickly fixes your current need, but it uses getdisplayValues(), which is a quick cheat to not have to deal with processing the date. You should probably modify this function so that it would work with other date formats. (Use getValues(), get the day, time and month from yesterday, then the same from each value in the for loop, and make sure to account for any timezone offsets.)

NSDate, extracting values from an array, converting from string to nsdate

first time here. I'm a beginner student at swift (and programming in general) and I'm trying to make a simple app which will show 5 time values based on current day. I've tried a lot of stuff, but just cannot develop logic here. I will copy paste code (which some of it is pseudocode).
import UIKit
class ViewController: UIViewController {
// TIME Values
let time1 = ["07:01", "07:03", "07:03"] // ..... Array continues for 365 days, every string value representing each day
let time2 = ["11:59", "11:59", "12:00"] // ..... Array continues for 365 days, every string value representing each day
let time3 = ["14:15", "14:16", "14:17"] // ..... Array continues for 365 days, every string value representing each day
let time4 = ["17:12", "17:13", "17:15"] // ..... Array continues for 365 days, every string value representing each day
let time5 = ["19:10", "19:11", "19:12"] // ..... Array continues for 365 days, every string value representing each day
// Current Date
let todaysDate = NSDate()
// Pseudocode to extract the value from time arrays...
choose a value from TIME Values based on todaysDate
print(time1) // single value from time1 array (converted from string to date/time value) based on todaysDate
print(time2) // single value from time1 array (converted from string to date/time value) based on todaysDate
print(time3) // single value from time1 array (converted from string to date/time value) based on todaysDate
print(time4) // single value from time1 array (converted from string to date/time value) based on todaysDate
print(time5) // single value from time1 array (converted from string to date/time value) based on todaysDate
// Final values should be NSDate (or similar) values, because of time manipulation
let timeCorrection1 = ["00:02", "00:03", "00:03"] // ..... Correction continues for 365 days, every string value representing each day
let timeCorrection2 = ["00:02", "00:03", "00:03"] // ..... Correction continues for 365 days, every string value representing each day
let timeCorrection3 = ["00:02", "00:03", "00:03"] // ..... Correction continues for 365 days, every string value representing each day
let timeCorrection4 = ["00:02", "00:03", "00:03"] // ..... Correction continues for 365 days, every string value representing each day
let timeCorrection5 = ["00:02", "00:03", "00:03"] // ..... Correction continues for 365 days, every string value representing each day
override func viewDidLoad() {
super.viewDidLoad()
}
}
So the idea is to get a value from a string array based on currentdate, and have that in nsdate format (in MM:hh style) so it can be manipulated later, since I would like to subtract or add values from other variables (ie 00:02).
I hope I was clear enough, thank you very much in advance!

getting specific object in fetchedObjects without iteration

My app has a custom object SSSchedule that I persist in CoreData, with a sortDescriptor of "date" (SSSchedule has a variable var date : NSDate?). Is there a more efficient method to finding a specific SSSchedule object with a specific date rather than iterating through the fetchedObjects array checking each for schedule.date == myDate as! NSDate?
My app references the fetchedObjects quite often, so I would imagine constantly mapping fetchedObjects to a dictionary of type [String : SSSchedule] (for example) every time the context is saved would affect performance...
Write a fetch request to return the objects matching that specific date from the datastore. If you are being consistent, then from what you've written you'll get back an array with one element.
Let Core Data do that searching for you. That's what it's for.
I think if you use a plist which has a Dictionary of Dictionaries. it could be a more what you need.
The first Dictionary will have a key of a tuple of (Day,Month,Year) which can be easily extracted from NSDate. and a value of a Dictionary which key is a tuple of (Hours, Minutes) also extracted from NSDate and a value of String which is the task to do at that time.
this way if you have a specific date, that date is the key to access only the tasks and events you have during that specific date in O(1) time complexity.
Now if you want to know if you have something at a specific time you access it in a similar way. The method is supposed to return String?. If there's a task at a specific time, it will return the task, otherwise it will return nil which means you're free at this time.
This is how the data structure should look [(Day, Month,Year):[(Hours,Minutes):String]]
Regarding extracting components from NSDate
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour |.CalendarUnitMinute
|.CalendarUnitYear|.CalendarUnitMonth|.CalendarUnitDay, fromDate: date)
let day = components.day
let month = components.month
let year = compononets.year
let hour = components.hour
let minutes = components.minutes
Use filter() to build a new array with any objects that match your criteria:
let newArray = fetchedObjects.filter() { $0.date == myDate as! NSDate }
Then check the count of newArray and handle accordingly - unless you know the dates are unique, there could be zero, one or more elements in the array.

iterate through array and store results

I have an array called thoughtArray which is an array of a custom object called ThoughtObject. ThoughtObject has a property called 'createdDate' which holds an NSDate, the date that the object was created.
I need to filter through that array and find all the objects that match the current date and then append them to another array.
So far all attempts have been unsuccessful. This is what i've tried below.
for createdToday in thoughtArray {
if (createdToday.createdDate?.isEqualToDate(NSDate()) != nil) {
createdTodayArray.append(createdToday)
}
}
The problem is that even objects that have the createdToday property set to a few days ago get added to the array.
Help would be greatly appreciated.
There are two problems. First, the "optional chaining"
createdToday.createdDate?.isEqualToDate(NSDate()
returns nil or not, depending on whether createdToday.createdDate
is nil or not. That is not what you want.
Second, as already stated by #thelaws in his answer, isEqualToDate()
returns only yes if the two dates represent exactly the same moment in time. NSCalendar has a
func compareDate(date1: NSDate, toDate date2: NSDate, toUnitGranularity unit: NSCalendarUnit) -> NSComparisonResult
method (available since iOS 8) which can be used here:
let cal = NSCalendar.currentCalendar()
let now = NSDate()
for createdToday in thoughtArray {
if let createdAt = createdToday.createdDate {
// compare with "day granularity":
if cal.compareDate(createdAt, toDate: now, toUnitGranularity: .CalendarUnitDay) == .OrderedSame {
createdTodayArray.append(createdToday)
}
}
}
An NSDate object represents a specific moment in time. Thus, it's very unlikely that a date in your array represents exactly NOW.
There are several approaches to determine if a date is today. You could turn the date into NSDateComponents and compare the year, month and day.
Use the compareDate function mentioned by Martin and the filter function of Array:
var thoughtArray = [ThoughtObject]()
var cal = NSCalendar.currentCalendar()
var createdToday = thoughtArray.filter {
if let createdDate = $0.createdDate {
return cal.compareDate(NSDate(), toDate: createdDate, toUnitGranularity: .CalendarUnitDay) == .OrderedSame
}
else {
return false;
}
}

Resources