Converting Firebase's ChildByAutoId timestamp to NSDate - ios

I used childByAutoId() save the timestamp as an auto-id. I can successfully retrieve the timestamp key that looks like -KJrs03bWbSTXfomqzMW. When I check the key's type, it says AnyObject.
let timestamps = snap.value.allKeys
for timestamp in timestamps {
print(timestamp) // -KJrs03bWbSTXfomqzMW
if let t = timestamp as? NSTimeInterval {
print(NSDate(timeIntervalSince1970: t/1000))
print("true")
} else {
print("false")
}
}
However, it goes into false bit.
What am I doing wrong? What is the proper way of converting Firebase timestamps to NSDate?
PS:
I remember I read Firebase allows for a global timing for the items with this kind of timestamp. Is there a way that would enable me to get human-readable version of the time, such as 30mins ago, 5 hrs ago directly working with Firebase or should I use NSDateFormatter?
The node looks like:
- -KJrs03bWbSTXfomqzMW
- "key1": "val"
- "key2": "val"

Related

Send timestamp to firebase using firebase funtions

I need to save a date has a firebase Timestamp Object to Cloud Firestore using Firebase functions.
The code in question:
import FirebaseFunctions
lazy var functions = Functions.functions(region: "europe-west3")
let stamp = Timestamp(date: Date()) —> Not working
self.functions.httpsCallable("userUpdate").call(["id": user.uid, “startDate”: stamp]) { (result, error) in
if let error = error {
print("##### update error \(error)”)
}
}
if let res = result {
if let fireData = (res.data as? [String: Any]) {
debugPrint("##### Success update Data -> \(fireData["data"])")
}
}
}
The problem is that Firebase does not recognise the Timestamp format throwing a error:
'Unsupported type: FIRTimestamp for value <FIRTimestamp: seconds=1633262425 nanoseconds=843380928>'
If I try to send the date on the format below it works BUT the date on the server has the wrong format, it shows has a string and not has a Timestamp.
let date = DateFormatter.localizedString(from: Date(), dateStyle: .short, timeStyle: .none)
Any solutions for Firebase to recognise the date I'm sending has a Timestamp?
Callable Cloud Functions only know how to send/receive JSON type, and Timestamp is not a JSON type.
The easiest way to work around this is to send the seconds and nanoseconds as separate numbers (which are valid JSON types) and then reconstruct a Timestamp object from those numberzs in the Cloud Functions code.

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

Storing AnyObject in array?

I've got an array that I'm trying to store timestamps into.
I'm testing stuff out with something like:
#IBAction func buttonPressed(sender:UIButton!) {
let post = ["MinutesLeft" : (FIRServerValue.timestamp())]
DataService.ds.REF_POSTS.childByAutoId().setValue(post)
}
Then I'm trying to call it back and fill an array with some of those timestamps:
DataService.ds.REF_POSTS.queryOrderedByChild("MinutesLeft").queryStartingAtValue(Int(cutoff)).observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
let post = snapshot.value!["MinutesLeft"]
print("POST \(post)" )
self.postsArray.append(post)
print(self.postsArray)
} else {
print("Didn't work")
}
})
Then I'm running a timer that's meant to clear out certain posts:
func removeExpiredItems() {
let cutoff = UInt64(1000 * floor(NSDate().timeIntervalSince1970) - 10*60*1000)
while (self.postsArray.count > 0 && self.postsArray[0] < cutoff) {
// remove first item, because it expired
self.postsArray.removeAtIndex(0)
print(postsArray.count)
}
}
My issues are :
I don't know what kind of array to have here. It's telling me that a timestamp is an AnyObject, but when I go to make an array of anyobjects I get a straight up Xcode internal error crash...so I guess that's a no-go.
I can translate it all to strings and just store it like that, but the issue comes then when I'm trying to compare the times vs my cutoff in my removeExpiredItems func.
I was trying to do something like:
Take the timestamps, change them to a string , then down when I'm going to make the comparison change the String to an Int but I get something like "This kind of conversion will always fail".
Any ideas here?
let post = snapshot.value!["MinutesLeft"]
The type of post will be AnyObject, (Optional<AnyObject>) in this case.
You have store it as the data type you want. For example in this case you can store it as NSTimeInterval
let post = snapshot.value!["MinutesLeft"] as! NSTimeInterval
And store it in an Array of NSTimeInterval as
var postsArray :[NSTimeInterval] = []

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.

Convert ISO 8601 strings to date in createOrUpdateInDefaultRealmWithObject

I have a block of JSON returned from a REST API in the following format:
[
{
id: 1,
locations: [
{
arriveAt: "2015-03-14T16:05:16Z"
},
{
arriveAt: null
]
},
...
]
I then have code in my project like this:
let trips = json as [NSDictionary]
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
for trip in trips {
Trip.createOrUpdateInDefaultRealmWithObject(trip)
}
realm.commitWriteTransaction()
In my Location class, there is a var dynamic var arriveAt: NSDate?. I also extended NSDate with a fromISO8601String method which initializes NSDate converting the ISO 8601 string to a date.
Is there a way that when Realm tries to create the Location object, it would automatically run the string from the JSON through NSDate.fromISO8601String?
Hi Dave there isn't anything built into Realm yet that can do that for you. You will need to use a transformer like Realm-JSON, or Mantle, etc.

Resources