import FSCalendar
import SwiftyJSON
import Alamofire
//import CalendarKit
import UIKit
struct PublicHoliday {
var name : String
var date : String
}
class ViewController: UIViewController, FSCalendarDelegate, FSCalendarDataSource {
#IBOutlet var calendar: FSCalendar!
#IBOutlet var contentsLabel: UILabel!
let formatter= DateFormatter()
var PH : [PublicHoliday]=[]
override func viewDidLoad() {
super.viewDidLoad()
calendarApi(year:"2020")
calendar.appearance.titleWeekendColor = UIColor.orange
calendar.allowsMultipleSelection = true
calendar.clipsToBounds = true
calendar.delegate = self
calendar.dataSource = self
}
func calendarApi(year:String){
let baseURLStr = "https://calendarific.com/api/v2/holidays"
let apiKey = "-------------------"
let urlStr = ["api_key":apiKey,"country":"KR","year":year]
//let urlStr = url + "api_key" +apiKey +"&country=KR"+"&year="+year
Alamofire.request(baseURLStr, method: .get, parameters: urlStr, encoding: URLEncoding.default).validate(statusCode:200..<300).responseJSON{
(response) in
switch response.result{
case .success(let value):
let jsonObject = JSON(value)
let count = jsonObject["response"]["PH"].count
for i in 0..<count {
let name = jsonObject["response"]["PH"][i]["name"].string!
let date = jsonObject["response"]["PH"][i]["date"]["iso"].string!
let ph = PublicHoliday(name: name, date: date)
self.PH.append(ph)
self.calendar.reloadData()
}
case .failure(_):
print("error")
}
}
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
formatter.dateFormat = "EEEE MM-dd-YYYY"
let string = formatter.string(from: date)
print("\(string)")
}
func calendar(_ calendar:FSCalendar, appearance:FSCalendarAppearance, fillDefaultColorFor date: Date)->UIColor?{
let dataForm = formatter.string(from:date)
for ph in self.PH{
if ph.date.compare(dataForm) == ComparisonResult.orderedSame{
return UIColor.cyan
}
}
return nil
}
func calendar(_ calendar: FSCalendar, subtitleFor date: Date) -> String? {
let dataForm = formatter.string(from: date)
for ph in self.PH{
if ph.date.compare(dataForm) == ComparisonResult.orderedSame{
return ph.name
}
}
return nil
}
}
In these two methods,
func calendar(_ calendar:FSCalendar, appearance:FSCalendarAppearance, fillDefaultColorFor date: Date)->UIColor?{
let dataForm = formatter.string(from:date)
for ph in self.PH{
if ph.date.compare(dataForm) == ComparisonResult.orderedSame{
return UIColor.cyan
}
}
return nil
}
func calendar(_ calendar: FSCalendar, subtitleFor date: Date) -> String? {
let dataForm = formatter.string(from: date)
for ph in self.PH{
if ph.date.compare(dataForm) == ComparisonResult.orderedSame{
return ph.name
}
}
return nil
}
You are comparing the string representations of the dates from the data source PH and the date parameter supplied by the datasource/delegate method of FSCalendar. However, you did not set a correct format (or any format at all, actually) for the formatter to use. This causes formatter.string(from:) to produce empty strings, so you are comparing empty strings with actual dates like 2020-12-25. From a brief look of the API documentation of the API that you are using, it seems like the dates come in the ISO 8601 local date format.
You should therefore, set a format like this:
func calendar(_ calendar:FSCalendar, appearance:FSCalendarAppearance, fillDefaultColorFor date: Date)->UIColor?{
formatter.dateFormat = "yyyy-MM-dd"
let dataForm = formatter.string(from:date)
for ph in self.PH{
if ph.date == dataFrom {
return UIColor.cyan
}
}
return nil
}
func calendar(_ calendar: FSCalendar, subtitleFor date: Date) -> String? {
formatter.dateFormat = "yyyy-MM-dd"
let dataForm = formatter.string(from: date)
for ph in self.PH{
if ph.date == dataFrom {
return ph.name
}
}
return nil
}
An even better approach would be to use Date in your data source directly:
struct PublicHoliday {
var name : String
var date : Date
}
And parse it when you get the response:
let dateString = jsonObject["response"]["PH"][i]["date"]["iso"].string!
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.date(from: dateString)!
let ph = PublicHoliday(name: name, date: date)
This way you can compare ph.date directly with the date supplied by FSCalendar.
Related
I have a form in which the user will select days and then select a date from calendar view..
for example: the user will first select sun and mon .. then click on date button an so calendar view will be shown ..
I want the user just be able to select dates in days sun or mon .. i want to disable the other days and highlight them for example ..
what is the best way to do that?
i saw these two libraries:
https://cocoapods.org/pods/JTAppleCalendar
https://github.com/WenchaoD/FSCalendar
but didn't find anything that helps me do what i need using them..
what is the best way to do that?
for JTApplecalendar this is easy
func calendar(_ calendar: JTAppleCalendarView, shouldSelectDate date: Date, cell: JTAppleCell?, cellState: CellState) -> Bool {
return cellState.day == .monday || cellState.day == .sunday
}
Done.
You have to consider Sunday as 1, Monday as 2, Tuesday as 3 and so on Saturday 7.
Define below globally
fileprivate let gregorian: Calendar = Calendar(identifier: .gregorian)
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
var arrDates = NSMutableArray()
Write below line in viewDidLoad.
arrDates = self.getUserSelectedDates([1, 2], calender: self.calendarVW)
Here 1, 2 means user selected Monday and Tuesday (so This array contains only those dates which are Sunday and Monday)
Below is Function that returns Dates array Based on Day value like 1,2 and so on till 7.
func getUserSelectedDates(_ arrWeekDay: [Int], calender calenderVW: FSCalendar?) -> NSMutableArray {
let arrUnAvailibilityDates = NSMutableArray()
let currentDate: Date? = calenderVW?.currentPage
//get calender
let gregorianCalendar = Calendar.init(identifier: .gregorian)
// Start out by getting just the year, month and day components of the current date.
var components: DateComponents? = nil
if let aDate = currentDate {
components = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aDate)
}
// Change the Day component to 1 (for the first day of the month), and zero out the time components.
components?.day = 1
components?.hour = 0
components?.minute = 0
components?.second = 0
//get first day of current month
var firstDateOfCurMonth: Date? = nil
if let aComponents = components {
firstDateOfCurMonth = gregorianCalendar.date(from: aComponents)
}
//create new component to get weekday of first date
var newcomponents: DateComponents? = nil
if let aMonth = firstDateOfCurMonth {
newcomponents = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aMonth)
}
let firstDateWeekDay: Int? = newcomponents?.weekday
//get last month date
let curMonth: Int? = newcomponents?.month
newcomponents?.month = (curMonth ?? 0) + 1
var templastDateOfCurMonth: Date? = nil
if let aNewcomponents = newcomponents {
templastDateOfCurMonth = gregorianCalendar.date(from: aNewcomponents)?.addingTimeInterval(-1)
}
// One second before the start of next month
var lastcomponents: DateComponents? = nil
if let aMonth = templastDateOfCurMonth {
lastcomponents = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aMonth)
}
lastcomponents?.hour = 0
lastcomponents?.minute = 0
lastcomponents?.second = 0
var lastDateOfCurMonth: Date? = nil
if let aLastcomponents = lastcomponents {
lastDateOfCurMonth = gregorianCalendar.date(from: aLastcomponents)
}
var dayDifference = DateComponents()
dayDifference.calendar = gregorianCalendar
if arrWeekDay.count == 0 {
} else if arrWeekDay.count == 1 {
let wantedWeekDay = Int(arrWeekDay[0])
var firstWeekDateOfCurMonth: Date? = nil
if wantedWeekDay == firstDateWeekDay {
firstWeekDateOfCurMonth = firstDateOfCurMonth
} else {
var day: Int = wantedWeekDay - firstDateWeekDay!
if day < 0 {
day += 7
}
day += 1
components?.day = day
firstWeekDateOfCurMonth = gregorianCalendar.date(from: components!)
}
var weekOffset: Int = 0
var nextDate: Date? = firstWeekDateOfCurMonth
repeat {
let strDT: String = getSmallFormatedDate(convertCalendarDate(toNormalDate: nextDate))!
arrUnAvailibilityDates.add(strDT)
weekOffset += 1
dayDifference.weekOfYear = weekOffset
var date: Date? = nil
if let aMonth = firstWeekDateOfCurMonth {
date = gregorianCalendar.date(byAdding: dayDifference, to: aMonth)
}
nextDate = date
} while nextDate?.compare(lastDateOfCurMonth!) == .orderedAscending || nextDate?.compare(lastDateOfCurMonth!) == .orderedSame
}
else {
for i in 0..<arrWeekDay.count {
let wantedWeekDay = Int(arrWeekDay[i])
var firstWeekDateOfCurMonth: Date? = nil
if wantedWeekDay == firstDateWeekDay {
firstWeekDateOfCurMonth = firstDateOfCurMonth
} else {
var day: Int = wantedWeekDay - firstDateWeekDay!
if day < 0 {
day += 7
}
day += 1
components?.day = day
firstWeekDateOfCurMonth = gregorianCalendar.date(from: components!)
}
var weekOffset: Int = 0
var nextDate: Date? = firstWeekDateOfCurMonth
repeat {
let strDT = getSmallFormatedDate(convertCalendarDate(toNormalDate: nextDate))
arrUnAvailibilityDates.add(strDT!)
weekOffset += 1
dayDifference.weekOfYear = weekOffset
var date: Date? = nil
if let aMonth = firstWeekDateOfCurMonth {
date = gregorianCalendar.date(byAdding: dayDifference, to: aMonth)
}
nextDate = date
} while nextDate?.compare(lastDateOfCurMonth!) == .orderedAscending || nextDate?.compare(lastDateOfCurMonth!) == .orderedSame
}
}
return arrUnAvailibilityDates
}
func getSmallFormatedDate(_ localDate: Date?) -> String? {
let dateFormatter = DateFormatter()
let timeZone = NSTimeZone(name: "UTC")
if let aZone = timeZone {
dateFormatter.timeZone = aZone as TimeZone
}
dateFormatter.dateFormat = "yyyy-MM-dd"
var dateString: String? = nil
if let aDate = localDate {
dateString = dateFormatter.string(from: aDate)
}
return dateString
}
func convertCalendarDate(toNormalDate selectedDate: Date?) -> Date? {
let sourceTimeZone = NSTimeZone(abbreviation: "UTC")
let destinationTimeZone = NSTimeZone.system as NSTimeZone
var sourceGMTOffset: Int? = nil
if let aDate = selectedDate {
sourceGMTOffset = sourceTimeZone?.secondsFromGMT(for: aDate)
}
var destinationGMTOffset: Int? = nil
if let aDate = selectedDate {
destinationGMTOffset = destinationTimeZone.secondsFromGMT(for: aDate)
}
let interval1 = TimeInterval((destinationGMTOffset ?? 0) - (sourceGMTOffset ?? 0))
var localDate: Date? = nil
if let aDate = selectedDate {
localDate = Date(timeInterval: interval1, since: aDate)
}
return localDate
}
Below is FSCalendar delegates
extension ViewController: FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance {
func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
self.view.layoutIfNeeded()
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
}
func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
arrDates = self.getUserSelectedDates([3, 4], calender: self.calendarVW)
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
if arrDates.contains(dateFormatter2.string(from: date)) {
return UIColor.green
} else {
return UIColor.red
}
}
func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
if arrDates.contains(dateFormatter2.string(from: date)) {
return true
}
else {
return false
}
}
}
For function calendar check Saturday or Sunday then it did not select.
The solution for Swift 4.2:
func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
return CheckSatSunday(today: date)
}
// Check Today Is Saturday or Sunday
func CheckSatSunday(today:Date) ->Bool{
var DayExist:Bool
// let today = NSDate()
let calendar =
NSCalendar(calendarIdentifier:NSCalendar.Identifier.gregorian)
let components = calendar!.components([.weekday], from: today)
if components.weekday == 1 {
print("Hello Sunday")
self.showToast(message: "Sunday is Off")
DayExist = false
} else if components.weekday == 7{
print("Hello Saturday")
self.showToast(message: "Saturday is Off")
DayExist = false
} else{
print("It's not Saturday and Sunday ")
DayExist = true
}
print("weekday :\(String(describing: components.weekday)) ")
return DayExist
}
How do I format this date so that it is readable. I want it to show for example: "January 7th, 2018 7:30am". I tried to look at other answers but wasn't sure where to add the extension.
let date = Date(timeIntervalSince1970: request.timestamp / 1000)
dateCell.textLabel?.text = date.description
class Request {
var key:String
var sender:String
var recipient:String
var name:String
var location:String
var when:String
var whereStr:String
var message:String
var timestamp:Double
var status:String
init(dict: [String: Any]) {
self.key = dict["key"] as? String ?? ""
self.sender = dict["sender"] as? String ?? ""
self.recipient = dict["recipient"] as? String ?? ""
self.name = dict["name"] as? String ?? ""
self.location = dict["location"] as? String ?? ""
self.when = dict["when"] as? String ?? ""
self.whereStr = dict["where"] as? String ?? ""
self.message = dict["message"] as? String ?? ""
self.timestamp = dict["timestamp"] as? Double ?? 0.0
self.status = dict["status"] as? String ?? ""
}
Try This
func getCurrentDateTimeFromTimeStamp(timeStapm:String)->String{
let date = NSDate(timeIntervalSince1970:Double(timeStapm)!/1000)
let formatter = DateFormatter()
formatter.dateFormat = "MMMM d, yyyy HH:mm a"
return formatter.string(from: date as Date)
}
pass timestamp and get as date in string format as per your requirement just pass dateFormat.
use like this
dateCell.textLabel?.text = self.getCurrentDateTimeFromTimeStamp(timeStapm:"pass your timestamp")
You should use DateFormatter:
let formatter = DateFormatter()
formatter.format = "MMMM d, yyyy HH:mm a"
let dateString = formatter.string(from: date)
Use a dateFormatter object to style the date however you want
let format = DateFormatter()
format.format = "MM/dd/yyyy"
//get your date in string like this
let dateInString = format.string(from: date)
// this will give you "10/02/2018"
You can visit date format examples to see different format and how to get them.
You can add extension anywhere in the app and one (same name) extension for comlpete app. look below
import UIKit
class ViewControllerHellBoy: UIViewController
{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
dateCell.textLabel?.text = self.userFriendlyFullDate()
}
}
extension Date: Dateable {
var formatter: DateFormatter { return DateFormatter() }
/** Return a user friendly hour */
func userFriendlyFullDate() -> String {
// Customize a date formatter
formatter.dateFormat = ""MMMM d, yyyy HH:mm a"" //Use format you want to
formatter.timeZone = TimeZone(abbreviation: "UTC") . // Time zone you wishes to provide
return formatter.string(from: self)
}
That is how you can use extensions. You can also create separate class and keep all extensions there.
How to display events on Fscalender?
This is my code to fetch events from api call.
func SetUpUIDashBoardCalenderdata()
{
APIManager.sharedInstance.FetchParentDashboardCalenderDataFromURL(){(dashBoardCalenderJson)-> Void in
let calenderVar = JSON(dashBoardCalenderJson)
print("calenderVar----",calenderVar)
let info = calenderVar["dates"].rawString()
let jsonData = info?.data(using: .utf8)!
let dictionary = try? JSONSerialization.jsonObject(with: jsonData!, options: []) as! Array<Any>
print("dictionary",dictionary)
}
}
You should implement FSCalendarDataSource protocol.
please take a look at my example :
let events = [Date]()
fileprivate lazy var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
return formatter
}()
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dayFormatted = dateFormatter.string(from: date)
var counter = 0
for event in events{
let day = dateFormatter.string(from: event)
if dayFormatted == day{
counter += 1
}
}
return counter
}
or shorter :
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dayFormatted = dateFormatter.string(from: date)
return events.filter({ dateFormatter.string(from: $0) == dayFormatted }).count
}
I am new to swift, Am using Fscalender in swift it's working fine, But I want add the Events to Fscalender, I can get events from Json
I Want Display the events in calender, I can try some of the code but its not working getting some errors pls help how to display events in calender
var EventsData = [Event]()
all events are stored Into Event
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
inside Json
if let event_list = jsonData["events"] as? NSArray {
for i in 0 ..< event_list.count {
if let event = event_list[i] as? NSDictionary {
let data = event["date"]as?String
let newString = data?.replacingOccurrences(of: "/", with: "-")
print("new string data ",newString as Any)
self.compareDate(date: newString!)
self.EventsData.append(Event(
eventId: event["eventId"] as? String,
eventName:event["details"] as? String,
//eventDate: event["date"] as? String
eventDate: newString ))
}
}
}
Display the Events
func compareDate(date : String){
let date = date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFromString : NSDate = dateFormatter.date(from: date)! as NSDate
===>> After this line showing Fatal error
dateFormatter.dateFormat = "yyyy-MM-dd"
let datenew = dateFormatter.string(from: dateFromString as Date)
print("datee",datenew)
}
func calendar(_ calendar: FSCalendar, willDisplay cell: FSCalendarCell, for date: Date, at position: FSCalendarMonthPosition) {
let dateFormatter3 = DateFormatter()
dateFormatter3.dateFormat = "yyyy-MM"
let dateString3 = dateFormatter3.string(from: date)
//print("datenew1",dateString3)
strcond = dateString3 as NSString
print("datenew1",strcond!)
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd"
let datenew = dateFormatter.string(from: dateFromString as Date)
if datenew.contains(dateString) {
return 1
}
}
return 0
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventColorFor date: Date) -> UIColor? {
let dateString = self.dateFormatter2.string(from: date)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd"
let datenew = dateFormatter.string(from: dateFromString as Date)
print("new calendar",dateString)
if datenew.contains(dateString) {
return UIColor.purple
}
}
return nil
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
if monthPosition == .previous || monthPosition == .next {
calendar.setCurrentPage(date, animated: true)
print("title date",date)
}
}
how to show events in calendar ?
After some changes in my code it's working fine showing events in FsCalender
inside Json
if let event_list = jsonData["events"] as? NSArray {
for i in 0 ..< event_list.count {
if let event = event_list[i] as? NSDictionary {
self.EventsData.append(Event(
eventId: event["eventId"] as? String,
eventName:event["details"] as? String,
eventDate: event["date"] as? String
)
)
}
}
self.do_refresh()
}
func do_refresh()
{
DispatchQueue.main.async(execute: {
self.calender.reloadData()
return
})
}
Fscalender Implementation
func calendar(_ calendar: FSCalendar, willDisplay cell: FSCalendarCell, for date: Date, at position: FSCalendarMonthPosition) {
let dateFormatter3 = DateFormatter()
dateFormatter3.dateFormat = "yyyy-MM-dd"
let dateString3 = dateFormatter3.string(from: date)
strcond = dateString3 as NSString
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
print("this count first ",self.EventsData.count)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let datenew = dateFormatter.string(from: dateFromString as Date)
if datenew.contains(dateString) {
return 3
}
}
return 0
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventColorFor date: Date) -> UIColor? {
let dateString = self.dateFormatter2.string(from: date)
for d in EventsData{
let date = d.eventDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let dateFromString : NSDate = dateFormatter.date(from: date!)! as NSDate
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let datenew = dateFormatter.string(from: dateFromString as Date)
if datenew.contains(dateString) {
return UIColor.init(red: 10, green: 200, blue: 399, alpha: 300)
}
}
return nil
}
How can I compare the values from data Base to my current date ? A date is saved in the data base when some action is performed, I need to compare that date with my current date and do some action. How can I do that ?
The date is saved my date base in this format:
var tasksin2 : Task?
dateFormatter.dateFormat = "dd/MM/yyyy hh:mm"
let mydate="\(dateFormatter.string(from: datePicker.date))"
tasksin2?.time=mydate
(UIApplication.shared.delegate as! AppDelegate).saveContext()
Here ya go:
extension String {
func toDate() -> Date? {
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy hh:mm"
return formatter.date(from: self)
}
}
class MyViewController: UIViewController {
var dateString1: String!
var dateString2: String!
override func viewDidLoad() {
super.viewDidLoad()
// set dateStrings
printDateTypes()
}
func printDateTypes() {
guard let date1 = dateString1.toDate() else {
print("dateString1: \(dateString1) | Failed to cast to \"dd/MM/yyyy hh:mm\"")
return
}
guard let date2 = dateString2.toDate() else {
print("dateString2: \(dateString2) | Failed to cast to \"dd/MM/yyyy hh:mm\"")
return
}
let isDescending = date1.compare(date2) == ComparisonResult.orderedDescending
print("orderedDescending: \(isDescending)")
let isAscending = date1.compare(date2) == ComparisonResult.orderedAscending
print("orderedAscending: \(isAscending)")
let isSame = date1.compare(date2) == ComparisonResult.orderedSame
print("orderedSame: \(isSame)")
}
}