Highlight day if the date equal to date in array (JTAppleCalendar) - swift

I have an array of object contains bookings
class MonthBookings: NSObject {
var date: Date = Date()
var bookings_count: Int = 0
}
var bookings = [MonthBookings]()
So I need to check if cell date is equal to some date in bookings array then change cell color for this date in cell.
I have tried this way down below but didn't work:
func calendar(_ calendar: JTAppleCalendarView, willDisplayCell cell: JTAppleDayCellView, date: Date, cellState: CellState) {
guard let sfbCell = cell as? SFBCalendarCell else {return}
let booking = self.bookingsMonths[cellState.row()]
if booking.date == date {
sfbCell.dayText.textColor = .red
} else {
sfbCell.dayText.textColor = .black
}
}

Are you doing a day compared or the actual date/Time?
Try something like this.
let order = CalendarManager.currentCalendar.compare(cellState.date, to:
Date(), toGranularity: .day)
if order == .orderedSame {
calendarCell.dayNumberLabel.textColor = UIColor.white
}

I Solved by using Contains method
if bookingsMonths.contains(where: { $0.date == cellState.date && $0.bookings_count != 0 }) {
sfbCell.dayText.font = UIFont.boldSystemFont(ofSize: 15)
} else {
sfbCell.dayText.font = UIFont.systemFont(ofSize: 15)
}

Related

Date comparison always returns true - Swift

I want to track when was the last time the user refreshed the api, so I decided to do it like this:
#AppStorage("lastTimeUserRefreshedApi") var lastTimeUserRefreshedApi: Date = Date()
func canUserRefreshAPI() -> Bool {
let readyToBeRefreshed: Date = lastTimeUserRefreshedApi.addingTimeInterval(5) // in seconds
let currentTime: Date = Date()
var canUserRefresh: Bool = false
if(currentTime > readyToBeRefreshed) {
canUserRefresh = true
lastTimeUserRefreshedApi = lastTimeUserRefreshedApi.addingTimeInterval(5)
} else {
canUserRefresh = false
}
return canUserRefresh
}
The problem is that it's always returning true, but why? Also is there a simpler way to do this?
Thanks
EDIT:
This is the extension I'm using to be able to store Date in the #AppStorage:
extension Date: RawRepresentable {
public var rawValue: String {
self.timeIntervalSinceReferenceDate.description
}
public init?(rawValue: String) {
self = Date(timeIntervalSinceReferenceDate: Double(rawValue) ?? 0.0)
}
}
You are making it much harder than it should. Just save the "expiration" date. When you read it just compare if it is past or not.
#AppStorage("expiration")
var expiration: Date = Date(timeIntervalSinceNow: 5)
func canUserRefreshAPI() -> Bool {
let now = Date()
if expiration < now {
expiration = Date(timeIntervalSinceNow: 5)
return true
} else {
return false
}
}

_startDate Date <unavailable; try printing with "vo" or "po">

I want to create a date variable but get the following response:
_startDate Date <unavailable; try printing with "vo" or "po">
The code i have is:
func createMileagesPDF() {
var _someDate: NSDate = NSDate()
self.someDate = Date()
guard (!exportYear.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && exportYear.count == 4) && cars.count > 0 else {
showAlert.toggle()
return
}
let _dateFormatter = DateFormatter()
//_dateFormatter.dateFormat = "dd-MM-yyyy"
let _startDateString = String(format: "01-01-%#", exportYear)
let _startDate = createdate() // = _dateFormatter.date(from: "01-12-2020 00:00:01")
let _x = createdate()
print("Create PDF")
}
func createdate() -> Date {
return Date()
}
What i want is an startdate based on an given year.
A string converted to an date.
When i do this in PlayGround it all works fine.
Thanks.

Comparing a formatted date with current

I am comparing dates from a file called "file.txt" to put into a tableView as a list. I have a date in the file as the current date as a test at the end. It reads it, but doesn't recognize it as the current date. I have a date formatter setting the format to "MM/dd/yyyy". The checks work correctly with dates before and after the current date being pulled from the phone.
import UIKit
import GoogleMaps
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var banner: UIImageView!
#IBOutlet weak var tableView: UITableView!
var arrayMarkers = [GMSMarker]()
var dictMarkers = [String:String]()
override func viewDidLoad() {
super.viewDidLoad()
banner.image = #imageLiteral(resourceName: "Branding_Iron_Banner")
tableView.estimatedRowHeight = 155.0
tableView.rowHeight = UITableViewAutomaticDimension
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
let currentDate = Date()
print(formatter.string(from: currentDate))
guard let path = Bundle.main.path(forResource: "file", ofType: "txt") else {
print("File wasn't found")
return
}
let filemgr = FileManager()
if filemgr.fileExists(atPath: path) {
print("Found the file to read from!")
}
guard let streamReader = StreamReader(path: path) else {
print("Dang! StreamReader couldn't be created!")
return
}
var lineCounter = 0
var lat = 0.0
var log = 0.0
var address = ""
var date = ""
var time = ""
var snip = ""
var snip2 = ""
var same = true
while !streamReader.atEof {
guard let nextLine = streamReader.nextLine() else {
print("Oops! Reached the end before printing!")
break
}
if(lineCounter % 5 == 0) {
lat = (nextLine as NSString).doubleValue
}
else if(lineCounter % 5 == 1) {
log = (nextLine as NSString).doubleValue
}
else if(lineCounter % 5 == 2) {
address = nextLine
}
else if(lineCounter % 5 == 3) {
date = nextLine
let fileDate = formatter.date(from: date)
if (currentDate.compare(fileDate!) == .orderedSame) {
snip2 = date
print("Same dates compare with current: \(String(describing: fileDate))")
same = true
}
if(fileDate?.compare(currentDate) == .orderedDescending) {
print("Date comes after current: \(String(describing: fileDate))")
snip2 = date
same = true
}
if(fileDate?.compare(currentDate) == .orderedAscending) {
same = false
}
}
else if(lineCounter % 5 == 4){
if(same == true) {
time = nextLine
let position = CLLocationCoordinate2DMake(lat, log)
let marker = GMSMarker(position: position)
marker.title = address
snip = snip2 + "\n"+time
marker.snippet = snip
arrayMarkers.append(marker)
print("\n\(String(describing: marker.title))")
same = false
}
}
lineCounter += 1
print("\(lineCounter): \(nextLine)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayMarkers.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 2
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
//print("Inside the assigning of table cells")
let marker = arrayMarkers[indexPath.row]
//print(marker.snippet!)
cell.textLabel?.text = marker.title
cell.detailTextLabel?.text = marker.snippet
return cell
}
}
The date I care about from my file is formatted as "06/07/2018" as is the format for the rest of my dates in my file.
Updated with output comparison:
74: 05/30/2018
75: 8:00 am to 5:00 pm
76: 41.313000
77: -105.576195
78: 1513 Fraternity Row
The current date is: 2018-06-08 15:32:22 +0000
The file date is: Optional(2018-06-08 06:00:00 +0000)
It is supposed to be ignoring the time after the formatting.
The issue is that compare on two Date instances compares down to the microsecond.
Your line let currentDate = Date() gives you an exact moment of "now" to the microsecond.
As you read the file and create a Date from the "MM/dd/yy" string, you get a Date to the microsecond of midnight local time on the given date.
So even if the two dates are on the same day, one is the current time and one is midnight local time.
With that explanation of why it isn't working out of the way, here's the simple fix. Update your comparison code to the following:
if Calendar.current.isDate(currentDate, inSameDayAs: fileDate!) {
snip2 = date
print("Same dates compare with current: \(String(describing: fileDate))")
same = true
} else if currentDate < fileDate! {
print("Date comes after current: \(String(describing: fileDate))")
snip2 = date
same = true
} else {
// Not the same or descending so it must be ascending
same = false
}

Charts' line chart doesn't render line chart properly

I'm using the Charts framework and I'm experiencing some very weird behavior in my line chart.
When I segue to the ChartViewContoller and the default selection has data, the chart renders normally:
but if I segue to this view controller when the default selection doesn't have any data and then select an item that has data, it looks like this:
1) segue to this:
2) then select an item that has data:
Of course viewDidLoad is called when I segue to the view controller and as long as the default selection has data when I segue to it, I can select another item that has data or doesn't and the chart will continue to render properly. So the difference appears to be in viewDidLoad but I've tried everything I can think of but nothing fixes the problem. Here's my viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(hexString: "232B35")
self.title = "1RM"
chartView.delegate = self
chartView.chartDescription?.enabled = false
let leftAxis = chartView.leftAxis
leftAxis.axisMinimum = 190
leftAxis.labelTextColor = NSUIColor.white
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.axisMinimum = 0
xAxis.granularity = 1
xAxis.axisLineWidth = 5
xAxis.valueFormatter = self
xAxis.labelTextColor = NSUIColor.white
chartView.configureDefaults()
chartView.rightAxis.enabled = false // this fixed the extra xAxis grid lines
chartView.backgroundColor = NSUIColor(red: 35/255.0, green: 43/255.0, blue: 53/255.0, alpha: 1.0)
fetchData()
chartView.setVisibleXRangeMaximum(7)
chartView.animate(yAxisDuration: 1.0)
}
here's what's happening in fetchData():
func fetchData() {
chartView.data = nil
let liftName = UserDefaults.selectedLiftForChart()
let liftEvents = dataManager.fetchLiftsEventsOfTypeByName(liftName)
guard liftEvents.count > 0 else {
chartView.noDataText = "There's no \(liftName) data to display"
shouldHideData = true
return }
// put them into a Dictionary grouped by each unique day
let groupedEvents = Dictionary(grouping: liftEvents, by: { floor($0.date.timeIntervalSince1970 / 86400) })
// grab the maximum 1RM from each day
let dailyMaximums = groupedEvents.map { $1.max(by: { $0.oneRepMax < $1.oneRepMax }) }
// MARK: - TODO: Fix the silly unwrapping
sortedLiftEvents = dailyMaximums.sorted(by: { $0?.date.compare(($1?.date)!) == .orderedAscending }) as! [LiftEvent]
let intervalBetweenDates: TimeInterval = 3600 * 24 // 3600 = 1 hour
let startDate = (sortedLiftEvents.first?.date)! - intervalBetweenDates
let lastDate = sortedLiftEvents.last?.date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d"
let dates:[Date] = intervalDates(from: startDate, to: lastDate!, with: intervalBetweenDates)
days = dates.map {dateFormatter.string(from: $0)}
generateLineData()
}
and finally, this is the generateLineData method:
func fetchData() {
chartView.data = nil
let liftName = UserDefaults.selectedLiftForChart()
let liftEvents = dataManager.fetchLiftsEventsOfTypeByName(liftName)
guard liftEvents.count > 0 else {
chartView.noDataText = "There's no \(liftName) data to display"
shouldHideData = true
return }
// put them into a Dictionary grouped by each unique day
let groupedEvents = Dictionary(grouping: liftEvents, by: { floor($0.date.timeIntervalSince1970 / 86400) })
// grab the maximum 1RM from each day
let dailyMaximums = groupedEvents.map { $1.max(by: { $0.oneRepMax < $1.oneRepMax }) }
// MARK: - TODO: Fix the silly unwrapping
sortedLiftEvents = dailyMaximums.sorted(by: { $0?.date.compare(($1?.date)!) == .orderedAscending }) as! [LiftEvent]
let intervalBetweenDates: TimeInterval = 3600 * 24 // 3600 = 1 hour
let startDate = (sortedLiftEvents.first?.date)! - intervalBetweenDates
let lastDate = sortedLiftEvents.last?.date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d"
let dates:[Date] = intervalDates(from: startDate, to: lastDate!, with: intervalBetweenDates)
days = dates.map {dateFormatter.string(from: $0)}
generateLineData()
}
I've tried putting chartView.setVisibleXRangeMaximum(7) in the method that sets the chart data and verified that chartView.visibleXRange is 7 each time the chart is rendered but it doesn't make a difference. I've also made sure that the max XRange is being set after the data is set for the chart.
Is there anything else I can try or is this perhaps a bug that hasn't been fixed yet?
Thanks
Well I finally figured it out. I knew from reading the documentation that some properties must be set after the chart data is handed to the chart. It was not entirely clear which properties but through lots of debugging and process of elimination I determined it was the xAxis properties that needed to be reset whenever the data changed.
Now, when the data is changed I call my new function:
func resetxAxis() {
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.axisMinimum = 0
xAxis.granularity = 1
xAxis.axisLineWidth = 5
xAxis.valueFormatter = self
}
This had been in my viewDidLoad method so I made the above method out of it and can call it any time it's needed.

Swift 3 - Receiving optional value when value be a string [duplicate]

This question already has answers here:
Cannot get rid of Optional() string
(5 answers)
Closed 5 years ago.
So I have this code that takes the date of when a time was posted and converts it to something like "5h" or "1d" ago. However, it is displaying in my application as something like this - Optional(1)h.
Here is the code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "admincell", for: indexPath) as! AdminHomeCell
let post = activities[indexPath.row]
print(post["path"])
//let image = images[indexPath.row]
//let imaged = post["path"] as! String
//let image = URL(string: imaged)
let username = post["username"] as? String
let title = post["title"] as? String
let date = post["date"] as! String
let description = post["text"] as? String
let location = post["location"] as? String
let dateFormater = DateFormatter()
dateFormater.dateFormat = "yyyy-MM-dd-HH:mm:ss"
let newDate = dateFormater.date(from: date)!
let from = newDate
let now = Date()
let components : NSCalendar.Unit = [.second, .minute, .hour, .day, .weekOfMonth]
let difference = (Calendar.current as NSCalendar).components(components, from: from, to: now, options: [])
if difference.second! <= 0 {
cell.postDate.text! = "now"
}
if difference.second! > 0 && difference.minute! == 0 {
cell.postDate.text! = "\(difference.second)s." // 12s.
}
if difference.minute! > 0 && difference.hour! == 0 {
cell.postDate.text! = "\(difference.minute)m."
}
if difference.hour! > 0 && difference.day! == 0 {
cell.postDate.text! = "\(difference.hour)h."
}
if difference.day! > 0 && difference.weekOfMonth! == 0 {
cell.postDate.text! = "\(difference.day)d."
}
if difference.weekOfMonth! > 0 {
cell.postDate.text! = "\(difference.weekOfMonth)w."
}
/*
let session = URLSession(configuration: .default)
let downloadPicTask = session.dataTask(with: image!) {
(data, response, error) in
if let e = error {
print("Error downloading image: \(e)")
} else {
if let res = response as? HTTPURLResponse {
if let image = data {
let pic = UIImage(data: image)
cell.postImage.image = pic
} else{
print("couldn't get image: image is nil")
}
} else {
print("Couldn't get response code")
}
}
}
*/
cell.postTitle.text = title
cell.postUser.text = username
cell.postDescription.text = description
cell.postLocation.text = location
cell.postDate.text = date
cell.postDescription.lineBreakMode = .byWordWrapping // or NSLineBreakMode.ByWordWrapping
cell.postDescription.numberOfLines = 0
//downloadPicTask.resume()
return cell
}
If there is anything I should change to make it simply display "1h", please let me know! Thanks!
Update Xcode to 8.3 or newer, there is a warning that you're printing an optional value instead of a normal one.
In your code you use DateComponents and all the fields are optional, like e.g. difference.hour. You're using ! before to extract the value to compare it, but it is not a good way as it crashes the app if the value isn't there.
What you should do is like this:
guard let hour = difference.hour,
let minute = difference.minute, [...] else { return cell }
// below code using hour as not optional
in the method for every optional value to safely unwrap it.
In Swift 3 all date components are optionals but you can safely unwrap all optionals which are specified in dateComponents(from:to:
I recommend to use local variables:
let difference = Calendar.current.dateComponents([.second, .minute, .hour, .day, .weekOfMonth], from: from, to: now)
let diffSec = difference.second!
let diffMin = difference.minute!
let diffHour = difference.hour!
let diffDay = difference.day!
let diffWeekOfMonth = difference.weekOfMonth!
if diffSec <= 0 {
cell.postDate.text! = "now"
}
if diffSec > 0 && diffMin == 0 {
cell.postDate.text! = "\(diffSec)s." // 12s.
}
if diffMin > 0 && diffHour == 0 {
cell.postDate.text! = "\(diffMin)m."
}
if diffHour > 0 && diffDay == 0 {
cell.postDate.text! = "\(diffHour)h."
}
if diffDay > 0 && diffWeekOfMonth == 0 {
cell.postDate.text! = "\(diffDay)d."
}
if diffWeekOfMonth > 0 {
cell.postDate.text! = "\(diffWeekOfMonth)w."
}
Nevertheless take a look at DateComponentsFormatter