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

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!

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]]

Finding difference of 2 DateTime Objects with different timezones?

I need to set the other object's timezone to match now object which has utc timezone.
I'm comparing two datetime objects but the 'difference' value does not match the expected value. Most likely down to the fact that both objects have different Time Zones (Utc & Bst).
void main() {
var now = new DateTime.now().toUtc();
print(now);
print(now.timeZoneName);
var other = DateTime.parse("2020-05-22 18:27:32.608069");
print(other);
print(other.timeZoneName);
var diff = now.difference(other);
print(diff);
}
output:
2020-05-22 19:26:39.169Z
UTC
2020-05-22 18:27:32.608
British Summer Time
1:59:06.561000
You don't want to convert, you want to read in a date/time as UTC.
Change
var other = DateTime.parse("2020-05-22 18:27:32.608069");
to
var other = DateTime.parse("2020-05-22 18:27:32.608069z");
If other is already constructed, you need to make a new object with DateTime.utc()
https://api.dart.dev/stable/2.8.2/dart-core/DateTime/DateTime.utc.html
var newDate = new DateTime.utc(other.year, other.month, other.day, other.hour, other.minute, other.second, other.millisecond, other.microsecond);

Use getters and setters to create string from 1-7 integers

I'm trying to take a 1-7 integer value and print out a day for each value with an enum.
I get an error in the class mapping from firestore, "isn't a field in the enclosing class"
So if 1 is passed in then "Monday" is given
if 2 is passed in then "Tuesday" is given
enum _Days {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
class HeadingItem implements ListItem {
String _weekday;
final int time;
final DocumentReference reference;
set day(int weekday) {
var value = _Days.values[weekday - 1].toString();
var idx = value.indexOf(".") + 1;
var result = value.substring(idx, value.length);
_weekday = result;
}
String get day {
return _weekday;
}
HeadingItem.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['day'] != null),
assert(map['time'] != null),
day = map['day'], // 'day' isn't a field in the enclosing class <--- this is the error that im stuck on...
time = map['time'];
HeadingItem.fromSnapshot(DocumentSnapshot snapshot) : this.fromMap(snapshot.data, reference: snapshot.reference);
}
Change
String get day {
return _weekday;
}
to this
String day = _weekday;
Notice that in your code, day is technically a set of methods of this that allows us to work with day as if it were a member of this; day is not actually a member.
Thus, in order for your initializer list to work as you intended it to, it would already need to have access to this in order to provide the functionality you want (for example, to set the value of the internal member _weekday).
However, as mentioned in the Language Tour of Dart in the section on Initializer Lists, the initializer list does not have access to this. Rather we should see the initializer list as values to assign to members of this during the instantiation.

Inserting into Array and comparing Dates Swift iOS Code

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.

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.

Resources