Can't get the necessary date - swift

I am trying to get the difference between dates in days. I have a problem translating dates to the desired format.
func daysBefore(_ date: String) -> Int {
let currentDate = Date()
let dateFormater = DateFormatter()
dateFormater.dateFormat = "dd.mm.YYYY"
guard let nextDate = dateFormater.date(from: date) else {
return 0
}
return currentDate.interval(ofComponent: .day, fromDate: nextDate)
}
extension Date {
func interval(ofComponent comp: Calendar.Component, fromDate date: Date) -> Int {
let currentCalendar = Calendar.current
guard let start = currentCalendar.ordinality(of: comp, in: .era, for: date) else { return 0 }
guard let end = currentCalendar.ordinality(of: comp, in: .era, for: self) else { return 0 }
return end - start
}
}
daysBefore("22.09.2019")
When I convert the date from String to Date in:
let currentDate = Date()
let dateFormater = DateFormatter()
dateFormater.dateFormat = "dd.mm.YYYY"
guard let nextDate = dateFormater.date(from: date) else {
return 0
}
I always get something like: 2018-12-22 21:09:00 +0000.
But expected(in example): 22.09.2019.

Related

Convert string time into date swift

I have json from rest API :
{
"status": "ok",
"query": {
"format": "json",
"kota": "703",
"tanggal": "2017-02-07"
},
"jadwal": {
"status": "ok",
"data": {
"ashar": "15:26",
"dhuha": "06:21",
"dzuhur": "12:10",
"imsak": "04:28",
"isya": "19:31",
"maghrib": "18:20",
"subuh": "04:38",
"tanggal": "Selasa, 07 Feb 2017",
"terbit": "05:54"
}
}
}
I want convert jadwal -> data -> ashar and other into Date format
I have this code,
extension String {
func convertToDate() -> Date? {
let arr = self.split(separator: ":")
guard
let hour = Int(arr.first ?? ""),
let minute = Int(arr.last ?? "")
else { return nil }
let component = DateComponents(hour: hour, minute: minute)
var cal = Calendar.current
guard let timezone = TimeZone(identifier: "Asia/Jakarta") else { return nil }
cal.timeZone = timezone
let date = cal.date(from: component)
return date
}
}
But i get this result on my console debug
ashar: 0001-01-01 08:27:48 +0000
i expect for example on asr/ashar = 2021-01-12 15:26:00 for Indonesia Time, do you guys have advice or something?
You can create an extension for string that returns a full date object by passing only the time string as follows.
extension String {
func createDateObjectWithTime(format: String = "HH:mm") -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
guard let dateObjectWithTime = dateFormatter.date(from: self) else { return nil }
let gregorian = Calendar(identifier: .gregorian)
let now = Date()
let components: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
var dateComponents = gregorian.dateComponents(components, from: now)
let calendar = Calendar.current
dateComponents.hour = calendar.component(.hour, from: dateObjectWithTime)
dateComponents.minute = calendar.component(.minute, from: dateObjectWithTime)
dateComponents.second = 0
return gregorian.date(from: dateComponents)
}
}
You can call the extension by:
let date = "15:26".createDateObjectWithTime()
Just get the current date and set hour and minute to the extracted values
extension String {
func convertToDate() -> Date? {
let arr = self.split(separator: ":")
guard
let hour = Int(arr.first ?? ""),
let minute = Int(arr.last ?? "")
else { return nil }
var cal = Calendar.current
guard let timezone = TimeZone(identifier: "Asia/Jakarta") else { return nil }
cal.timeZone = timezone
return cal.date(bySettingHour: hour, minute: minute, second: 0, of: Date())
}
}

swift 4.2 how to correctly check time elapsed

I need to check a date before downloading / manipulate some data from a server. Let's say I need to do that only if 24 hours or more are gone by. this code seems to work, but I'm not sure about it, no way to do it with less lines of code? it seems to be too long to me. i checked this but solutions are quite different from mine.
import UIKit
//standard day formatter
let dateFormatter = DateFormatter()
//let's say this is the date I saved last time i updated data from online server:
let previousDate: String = "2019-03-19 06:40 PM"
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm a"
let old = dateFormatter.date(from: previousDate)
//today I try to download data
let today = Date()
//this simply tests if "moment before" is greater than "moment after"
if today > old! {
print("update data")
} else {
print("do not update")
}
//here I create a measure
let minute:TimeInterval = 60.0
let hour:TimeInterval = 60.0 * minute
let day:TimeInterval = 24 * hour
//here I measure if the old date added of 24h is greater than now, in that case a day or more is passed and I can update
let theOldDateMore24h = Date(timeInterval: day, since: old!)
if theOldDateMore24h < today {
print("passed more than a day: Update!")
} else {
print("less than a day, do not update")
}
There is a method in Calendar
func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents
Get the day component and check greater than 0
let dateFormatter = DateFormatter()
let previousDate = "2019-03-19 06:40 PM"
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm a"
let old = dateFormatter.date(from: previousDate)
//today I try to download data
let today = Date()
if let validDate = old, Calendar.current.dateComponents([.day], from: validDate, to: today).day! > 0 {
print("passed more than a day: Update!")
} else {
print("less than a day, do not update")
}
Quick extension function to simplify it:
extension Date {
func isWithin(_ distanceTime: TimeInterval, after laterDate: Date) -> Bool{
let distance = timeIntervalSince(laterDate)
let result = distanceTime >= distance
return result
}
}
//Usage
let secondsInDay = TimeInterval(60 * 60 * 24)
let isUpToDate = Date().isWithin(secondsInDay, after: previousDate)
if !isUpToDate {
print("passed more than a day: Update!")
}
else {
print("less than a day, do not update")
}
You can actually use an extension for this. It will return the required calendar component
Extension
extension Date {
func interval(ofComponent comp: Calendar.Component, fromDate date: Date) -> Int {
let currentCalendar = Calendar.current
guard let start = currentCalendar.ordinality(of: comp, in: .era, for: date) else { return 0 }
guard let end = currentCalendar.ordinality(of: comp, in: .era, for: self) else { return 0 }
return end - start
}
}
Usage
let yesterday = Date(timeInterval: -86400, since: Date())
let tomorrow = Date(timeInterval: 86400, since: Date())
// Change the component to your preference
let difference = tomorrow.interval(ofComponent: .day, fromDate: yesterday) // returns 2

How to hide next day with FSCalendar based on week

Hi I want to hide the next business day, if user registration date and current date both are same. I need to hide next working day.
Sunday and Saturday are holidays.
I write code following if user is register on Friday I need to hide Monday, how to resolve this problem.
I write like this how to hide businessday
func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
let joingdate = "2019-01-30" //modeldata.joindate
let currentdate = date.toString(dateFormat: "yyyy-MM-dd")
let currentDate = date
let currentdayweek = date.toString(dateFormat: "EEEE")
if joingdate == currentdate
{
if currentdayweek == "Friday"{
let businessday = Calendar.current.date(byAdding: .day, value: 3, to: currentDate)
return false
}
else if currentdayweek == "Saturday"{
let businessday = Calendar.current.date(byAdding: .day, value: 2, to: currentDate)
return false
}
else if currentdayweek == "Sunday"{
let businessday = Calendar.current.date(byAdding: .day, value: 1, to: currentDate)
return false
}
else
{
let businessday = Calendar.current.date(byAdding: .day, value: 1, to: currentDate)
return false
}
}
}
func minimumDate(for calendar: FSCalendar) -> Date {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let myString = formatter.string(from: Date())
let yourDate = formatter.date(from: myString)
formatter.dateFormat = "yyyy-MM-dd"
let strCurrentDate = formatter.string(from: yourDate!)
var addDay = 0
if let model = modeldata{
if let joiningdate = "2019-01-31"
{
if strCurrentDate == joiningdate
{
addDay = 2
}
let currentdayweek = yourDate!.toString(dateFormat: "EEEE")
if currentdayweek == "Friday"{
addDay = 4
}
else if currentdayweek == "Saturday"{
addDay = 3
}
else if currentdayweek == "Sunday"{
addDay = 2
}
}
}
let tomorrow = Calendar.current.date(byAdding:
.day, // updated this params to add hours
value: addDay,
to: formatter.date(from: strCurrentDate)!)
return tomorrow!
}
}

How to get day and month from Date type - swift 4

I have variable with data type Date, where I have stored date in this format
2018-12-24 18:00:00 UTC
How can I get from this day or month?
Details
Xcode Version 11.0 (11A420a), Swift 5
Links
How to convert string to Date
Solution
extension Date {
func get(_ components: Calendar.Component..., calendar: Calendar = Calendar.current) -> DateComponents {
return calendar.dateComponents(Set(components), from: self)
}
func get(_ component: Calendar.Component, calendar: Calendar = Calendar.current) -> Int {
return calendar.component(component, from: self)
}
}
Usage
let date = Date()
// MARK: Way 1
let components = date.get(.day, .month, .year)
if let day = components.day, let month = components.month, let year = components.year {
print("day: \(day), month: \(month), year: \(year)")
}
// MARK: Way 2
print("day: \(date.get(.day)), month: \(date.get(.month)), year: \(date.get(.year))")
Is that String or Date type?
if it is date you can do so:
let calendarDate = Calendar.current.dateComponents([.day, .year, .month], from: date)
that will give you the day, year and month
If you saved "2018-12-24 18:00:00 UTC" as a String, you can try this:
let dateString = "2018-12-24 18:00:00 UTC"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss 'UTC'"
guard let date = formatter.date(from: dateString) else {
return
}
formatter.dateFormat = "yyyy"
let year = formatter.string(from: date)
formatter.dateFormat = "MM"
let month = formatter.string(from: date)
formatter.dateFormat = "dd"
let day = formatter.string(from: date)
print(year, month, day) // 2018 12 24
Best Wishes!
The date string is not ISO8601 compliant, nevertheless you can use ISO8601DateFormatter if you replace <space> + UTC with Z and use custom format options.
Create a Date from the string and get the DateComponents for day and month
let string = "2018-12-24 18:00:00 UTC"
let formatter = ISO8601DateFormatter()
let trimmedString = string.replacingOccurrences(of: "\\s?UTC", with: "Z", options: .regularExpression)
formatter.formatOptions = [.withFullDate, .withFullTime, .withSpaceBetweenDateAndTime]
if let date = formatter.date(from: trimmedString) {
let components = Calendar.current.dateComponents([.day, .month], from: date)
let day = components.day!
let month = components.month!
print(day, month)
}
This is how I did in swift 4. I have a Billing class with "billDate" a field that contains the date.
extension Billing:Identifiable{
func month() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM"
if let inputDate = billDate {
let month = dateFormatter.string(from: inputDate)
return month.uppercased()
}
return ""
}
Extention Date All Time RETURN String:
extension Date {
func dateDistance(_ startDate: Date = Date()) -> String {
var remainingTime = ""
let dateValue = Calendar.current.dateComponents([.year,.month,.weekOfMonth,.day,.hour,.minute,.second], from: startDate, to: self)
remainingTime = String(format: "%2d Y - %2d M - %2d W - %2d D\n%02d:%02d:%02d",
dateValue.year ?? 0,
dateValue.month ?? 0,
dateValue.weekOfMonth ?? 0,
dateValue.day ?? 0,
dateValue.hour ?? 0,
dateValue.minute ?? 0,
dateValue.second ?? 0
)
return remainingTime
}
}
extension Date {
func getRemainingDayMonthYear (_ startDate: Date = Date()) -> String
{
var remainingTime = ""
let dateValue = Calendar.current.dateComponents([.year,.month,.weekOfMonth,.day,.hour,.minute,.second], from: startDate, to: self)
if dateValue.year ?? 0 > 0 {
remainingTime = dateValue.year ?? 0 > 1 ? String(format: "%2d Years",dateValue.year ?? 0) : String(format: "%2d Year",dateValue.year ?? 0)
} else if dateValue.month ?? 0 > 0 {
remainingTime = dateValue.month ?? 0 > 1 ? String(format: "%2d Months",dateValue.month ?? 0) : String(format: "%2d Month",dateValue.month ?? 0)
} else {enter code here
remainingTime = dateValue.day ?? 0 > 1 ? String(format: "%2d Days",dateValue.day ?? 0) : String(format: "%2d Day",dateValue.day ?? 0)
}
return remainingTime
}
}
If you have a date variable you can also use this solution for SwiftUi:
let date = Date()
Text(date, style: .time) // January 8, 2023
Text(date, style: .date) // 12:08 PM

How to get all days in current week in swift

I am making an application where I need to get the day of the year for all days in the current week.
To achieve this, I am looking for a result similar to below (Today is Thursday the 23rd of March)
Monday = 79
Tuesday = 80
Wednesday = 81
Thursday = 82
Friday = 83
Saturday and Sunday can be included, however my application only needs weekdays rather then weekends. Today is day 82
To get the weekdays of the week, it is:
let calendar = Calendar.current
let today = calendar.startOfDay(for: Date())
let dayOfWeek = calendar.component(.weekday, from: today)
let dates = calendar.range(of: .weekday, in: .weekOfYear, for: today)!
.compactMap { calendar.date(byAdding: .day, value: $0 - dayOfWeek, to: today) }
.filter { !calendar.isDateInWeekend($0) }
To display that as “Thursday = 82”, it is:
let formatter = DateFormatter()
formatter.dateFormat = "eeee' = 'D"
for date in dates {
print(formatter.string(from: date))
}
Or
let strings = dates.map { formatter.string(from: $0) }
If you want it to consider firstWeekday (generally only a concern if you are no longer filtering weekends out of the results, hence no filter on isDateInWeekend, below):
let calendar = Calendar.current
let today = calendar.startOfDay(for: Date())
let todaysDayOfWeek = calendar.component(.weekday, from: today)
guard
let weekdaysRange = calendar.range(of: .weekday, in: .weekOfYear, for: today),
let index = weekdaysRange.firstIndex(of: calendar.firstWeekday)
else { return }
let weekdays = weekdaysRange[index...] + weekdaysRange[..<index].map { $0 + weekdaysRange.count }
let dates = weekdays.compactMap { calendar.date(byAdding: .day, value: $0 - todaysDayOfWeek, to: today) }
I had problems with adapting Rob's solution for when the week starts on Monday. This solution adapts to your calendar.firstWeekday setting.
var calendar = Calendar.autoupdatingCurrent
calendar.firstWeekday = 2 // Start on Monday (or 1 for Sunday)
let today = calendar.startOfDay(for: Date())
var week = [Date]()
if let weekInterval = calendar.dateInterval(of: .weekOfYear, for: today) {
for i in 0...6 {
if let day = calendar.date(byAdding: .day, value: i, to: weekInterval.start) {
week += [day]
}
}
}
return week
I made a small extension on Calendar, which might be helpful for anyone else looking for a more functional solution to this.
import Foundation
extension Calendar {
func intervalOfWeek(for date: Date) -> DateInterval? {
dateInterval(of: .weekOfYear, for: date)
}
func startOfWeek(for date: Date) -> Date? {
intervalOfWeek(for: date)?.start
}
func daysWithSameWeekOfYear(as date: Date) -> [Date] {
guard let startOfWeek = startOfWeek(for: date) else {
return []
}
return (0 ... 6).reduce(into: []) { result, daysToAdd in
result.append(Calendar.current.date(byAdding: .day, value: daysToAdd, to: startOfWeek))
}
.compactMap { $0 }
}
}
You could also use enumerateDates like this:
func getAllDaysOfTheCurrentWeek() -> [Date] {
var dates: [Date] = []
guard let dateInterval = Calendar.current.dateInterval(of: .weekOfYear,
for: Date()) else {
return dates
}
Calendar.current.enumerateDates(startingAfter: dateInterval.start,
matching: DateComponents(hour:0),
matchingPolicy: .nextTime) { date, _, stop in
guard let date = date else {
return
}
if date <= dateInterval.end {
dates.append(date)
} else {
stop = true
}
}
return dates
}