How to check if date is at least previous day? - ios

Hi everyone I'm trying to get a positive answer when comparing a date earlier than today
To do this I am using a Date extension with this boolean
extension Date {
var isPreviousDate: Bool {
return self.timeIntervalSinceNow.sign == .minus
}
}
Here is my problem .. when I print the date to compare it tells me that today's date is earlier and I don't understand why
Since I'm having problems I tried to create a current date and compare it with today's date the answer is that today's date is earlier than today ... this is weird because it shouldn't tell me it's older
This is how I create the date to compare
var calendar = Calendar(identifier: Calendar.current.identifier)
calendar.timeZone = NSTimeZone(name: "UTC")! as TimeZone
guard let selectedDate = calendar.date(from: DateComponents(year: Date().currentYear, month: Date().currentMonth, day: Date().currentDate)) else { return }
print("isPrevious Date :",selectedDate.isPreviousDate)
print(selectedDate)
am I doing something wrong?
this is what I read in the console when I print the created date to compare
isPrevious Date: true
2021-02-11 00:00:00 +0000

timeIntervalSinceNow is a FloatingPoint value with a very high precision, that represents seconds passed since the Date.
To check if current date is at least on a previous day, you could do something like this:
extension Date {
var isAtLeastPreviousDay: Bool {
return isPast && !isToday
}
private var isPast: Bool {
return self < Date()
}
private var isToday: Bool {
return Calendar.current.isDateInToday(self)
}
}

The issue there is that you are using a custom calendar using UTC timezone. You should use the current calendar with the current timezone. Note that you can use Calendar method startOfDay to get the start of day of a specific date:
extension Date {
var isPreviousDate: Bool {
timeIntervalSinceNow.sign == .minus
}
var startOfDay: Date {
Calendar.current.startOfDay(for: self)
}
}
let now = Date()
let startOfDay = now.startOfDay
print("isPrevious Date:", startOfDay.isPreviousDate) // true
If you would like to check if a date is in yesterday all you need is to use calendar method isDateInYesterday:
extension Date {
var isDateInYesterday: Bool {
Calendar.current.isDateInYesterday(self)
}
}
Date().isDateInYesterday // false
Date(timeIntervalSinceNow: -3600*24).isDateInYesterday // true

Related

Convert UTC time to PST in SWIFT

I need to convert the UTC time to PST
From backed, I get UTC dates like "2021-06-25T07:00:00Z"
I need to show the dates in Hstack from Provided UTC date to the current date.
I write the following code.
Anyone help to me.
func datesRange(from:Date, to:Date)->[Date]{
if from > to {return [Date]()}
var tmpdate = from
var array:[Date] = []
while tmpdate <= to {
array.append(tmpdate)
tmpdate = Calendar.current.date(byAdding: .day,value: 1, to: tmpdate)!
}
return array
}
extension Date{
func convertTimezone(timezone:String)-> Date{
if let targettimeZone = TimeZone(abbreviation: timezone){
let delta = TimeInterval(targettimeZone.secondsFromGMT(for: self) - TimeZone.current.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}else{
return self
}
}
}
I used as follows
func getrangeDays(){
let startday = "2021-06-25T07:00:00Z"
let dateformater = DateFormatter()
dateformater.locale = Locale(identifier: "en_US_POSIX")
dateformater.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
if let date = dateformater.date(from: startday){
let rangedays = datesRange(from:date.convertTimezone(timezone: "PST") , to: Date().convertTimezone(timezone: "PST"))
print(rangedays)
}
}
Your convertTimezone() function does not make sense. It is trying to convert a Date to a different time zone. A Date object does not have a time zone. It is an instant in time, anywhere on the planet. Time zones only make sense when you want to display a Date, or do time zone specific date calculations. (And in that case you want to create a Calendar object and set its time zone to the desired time zone, then use that Calendar for your date calculations.)
Get rid of that function.
Convert your input date string to a Date as you are doing now (although you might want to use an ISO8601DateFormatter rather than a regular date formatter, since those are specifically intended for handling ISO8601 dates.)
Build your date range using your datesRange() function.
Then use a second DateFormatter to display your dates in PST. (Not convert Dates to PST. That doesn't make sense.)

Trouble Initializing TimeZone from TimeZone.abbreviation()

I am storing user birth dates on my backend via storing a date component dictionary. It looks something like this:
{
"day": 1,
"month": 1,
"year": 1970,
"timeZone": "GMT"
}
To store this object, it grabs the user's birth day, month, and year from user input. The user time zone, however, is gathered via TimeZone.current.abbreviation().
Now, some of my user birthdate objects on my backend have their "timeZone" formatted as "CST", "BST", or "PDT". "timeZone"s that are formatted this way successfully initialize a TimeZone on the front end via let timeZone = TimeZone(abbreviation: "CST")!, let timeZone = TimeZone(abbreviation: "BST")!, or let timeZone = TimeZone(abbreviation: "PDT")!, respectively.
The problem is, other user birthdate objects on my backend have their "timeZone" formatted as "GMT+8". When trying to initialize "timeZone"s formatted like this via let timeZone = TimeZone(abbreviation: "GMT+8")!, the initialization returns nil. I also tried let timeZone = TimeZone(identifier: "GMT+8")!, but this returns nil as well.
Is there a way to initialize a TimeZone when it is formatted with respect to its offset to GMT as opposed to its unique abbreviation? I've seen a TimeZone initializer that is TimeZone(secondsFromGMT: Int). Could I simply take the 8 from "GMT+8" and multiply it by 3600 (the number of seconds in an hour) and pass this result to TimeZone(secondsFromGMT: Int)?
I ended up writing code that adapts my application to account for these unexpected fringe cases where a TimeZone's abbreviation is formatted like "GMT+8" rather than "SGT". I created an extension to TimeZone:
extension TimeZone {
static func timeZone(from string: String) -> TimeZone {
//The string format passed into this function should always be similar to "GMT+8" or "GMT-3:30"
if string.contains("±") {
//This case should always be "GMT±00:00", or simply GMT
return TimeZone(secondsFromGMT: 0)!
} else {
//If the string doesn't contain "±", then there should be some offset. We will split the string into timeZone components. "GMT+8" would split into ["GMT", "8"]. "GMT-3:30" would split int ["GMT","3","30"]
let timeZoneComponents = string.components(separatedBy: CharacterSet(charactersIn: "+-:"))
var isAheadOfGMT: Bool!
//Check if the string contains "+". This will dictate if we add or subtract seconds from GMT
if string.contains("+") {
isAheadOfGMT = true
} else {
isAheadOfGMT = false
}
//Grab the second element in timeZoneElements. This represents the offset in hours
let offsetInHours = Int(timeZoneComponents[1])!
//Convert these hours into seconds
var offsetInSeconds: Int!
if isAheadOfGMT {
offsetInSeconds = offsetInHours * 3600
} else {
offsetInSeconds = offsetInHours * -3600
}
//Check if there is a colon in the passed string. If it does, then there are additional minutes we need to account for
if string.contains(":") {
let additionalMinutes = Int(timeZoneComponents[2])!
let additionalSeconds = additionalMinutes * 60
offsetInSeconds += additionalSeconds
}
//Create a TimeZone from this calculated offset in seconds
let timeZoneFromOffset = TimeZone(secondsFromGMT: offsetInSeconds)!
//Return this value
return timeZoneFromOffset
}
}
}
It is used like so:
let json: [String:String] = ["timeZone":"GMT+8"]
let timeZone = json["timeZone"]
let birthDate: BirthDate!
if let timeZoneFromAbbrev = TimeZone(abbreviation: timeZone) {
birthDate = BirthDate(day: birthDay, month: birthMonth, year: birthYear, timeZone: timeZoneFromAbbrev)
} else {
let timeZoneFromOffset = TimeZone.timeZone(from: timeZone)
print(timeZoneFromOffset.abbreviation())
//Prints "GMT+8"
birthDate = BirthDate(day: birthDay, month: birthMonth, year: birthYear, timeZone: timeZoneFromOffset)
}
My BirthDate class for context:
class BirthDate {
var day: Int
var month: Int
var year: Int
var timeZone: TimeZone
init(day: Int, month: Int, year: Int, timeZone: TimeZone) {
self.day = day
self.month = month
self.year = year
self.timeZone = timeZone
}
}
Time zones are funny things to work with. If anybody sees issue with the TimeZone extension above, please let me know. I think I've accounted for all scenarios, but could be mistaken.

Swift convert string to date output wrong date

I want to convert dateStartString = “28/02/2018” in to Date and compare that converted date with today date. when i convert dateStartString the converted date is "2018-02-27 18:30:00 UTC".why its output is wrong date?
here is my code
var dateStartString = "28/02/2018"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
guard let dateStartDate = dateFormatter.date(from: dateStartString) else {
fatalError("ERROR: Date conversion failed due to mismatched format.")
}
let dateToday = Date()
if(dateStartDate>=dateToday){
print("Yes")
}
else{
print("Today date is 28/02/2018. Why it print No?")
}
Hope you understand my problem.
Thanks in advance.
You need to understand that Date does not only represent a date, but also a time.
>= compares both date and time components of a Date object. Since you didn't specified any time in your date string, the API assumed it to be 00:00:00 in your local time, which is 18:30:00 of the previous day in UTC. Why UTC, you ask? That's what the description of the date always is. When you print a date, it always prints it in UTC time. To print it in your time zone, set the timeZone property of your date formatter and format it.
One way to only compare the date components is by removing the time components. From this answer, this is how you remove time components:
public func removeTimeStamp(fromDate: Date) -> Date {
guard let date = Calendar.current.date(from: Calendar.current.dateComponents([.year, .month, .day], from: fromDate)) else {
fatalError("Failed to strip time from Date object")
}
return date
}
Now this should be true:
dateStartDate >= removeTimeStamp(fromDate: dateToday)
As Sweeper explained, dateStartDate is at 00:00 of 28/02/2018,
whereas dateToday is the current point in time, which is
on the same day, but after midnight. Therefore dateStartDate >= dateToday evaluates to false.
To compare the timestamps only to day granularity and ignore the
time components you can use
if Calendar.current.compare(dateStartDate, to: dateToday, toGranularity: .day) != .orderedAscending {
print("Yes")
}
This will print "Yes" if dateStartDate is on the same or a later
day than dateToday.
The compare method returns .orderedAscending, .orderedSame,
or .orderedDescending, depending on wether the first date is on
a previous day, the same day, or a later day, than the second date.
try to set your current date Formatter while comapring date.
Below your sample code update:
var dateStartString = "28/02/2018"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
dateFormatter.locale = NSLocale.current
guard let dateStartDate = dateFormatter.date(from: dateStartString) else {
fatalError("ERROR: Date conversion failed due to mismatched format.")
}
var dateToday = Date()
print(dateToday)
let dateTodaystr = dateFormatter.string(from: dateToday)
dateToday = dateFormatter.date(from: dateTodaystr)!
print(dateToday)
if(dateStartDate>=dateToday){
print("Yes")
}
else{
print("Today date is 28/02/2018. Why it print No?")
}
You need to timeZone for your dateFormatter:
dateFormatter.timeZone = TimeZone(secondsFromGMT:0)!

Date from string is not coming properly and two dates difference also using Swift 3?

I have a date in string format, example:- "2017-07-31" or can be multiple dates (any) in string format. My requirement is to check this date to current date and if it is greater than 0 and less than 15, then that time I have to do another operation.
So first I am converting that date string to in date format. But it is giving one day ago date. Here is my code:
//Date from string
func dateFromString(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let currentDate = (dateFormatter.date(from: date))//(from: date))
return currentDate!
}
Ex. my date is "2017-08-30" and this function is returning 2017-08-29 18:30:00 +0000 in date format. It means 1 day ago. I am little bit confuse about dates operation. I read so many blogs also.
After that I have to check this date to current date if it is in between 0 < 15 than I will do other operation.
Comparing two dates:
extension Date {
func daysBetweenDate(toDate: Date) -> Int {
let components = Calendar.current.dateComponents([.day], from: self, to: toDate)
return components.day ?? 0
}
}
If my date is today date and comparing to tomorrow date then also it is giving 0 days difference. Why?
If – for example – the current date is 2017-07-31 at 11AM then the
difference to 2017-08-01 (midnight) is 0 days and 13 hours, and that's
why you get "0 days difference" as result.
What you probably want is to compare the difference between the start
of the current day and the other date in days:
extension Date {
func daysBetween(toDate: Date) -> Int {
let cal = Calendar.current
let startOfToday = cal.startOfDay(for: self)
let startOfOtherDay = cal.startOfDay(for: toDate)
return cal.dateComponents([.day], from: startOfToday, to: startOfOtherDay).day!
}
}
Try this method for convert string to date:
func dateFromString(date : String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.timeZone = TimeZone.init(abbreviation: "UTC")
let currentDate = (dateFormatter.date(from: date))//(from: date))
return currentDate!
}
Try this to compare the time between two dates in seconds :
var seconds = Calendar.current.dateComponents([.second], from: date1!, to: date2!).second ?? 0
seconds = abs(seconds)
let min = seconds/60 // this gives you the number of minutes between two dates
let hours = seconds/3600 // this gives you the number of hours between two dates
let days = seconds/3600*24 // this gives you the number of days between two dates

Check if Date from Array of Dates is Date in Today (Swift)

I've got an array of 'reminders'. Reminder is a custom class that I wrote by myself which has got a property .fireDate.
How could I check if one of the reminders .fireDate properties is the same date as today?
let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
for (idx, date) in dates.enumerated() {
if calendar.isDateInToday(date) {
print("today at index \(idx)!")
}
}
Get the index of the first item whose fireDate is in today. If it's not nil there is at least one item.
let calendar = Calendar.current
if let indexOfFirstReminderWhichFiresToday = reminders.index(where: { calendar.isDateInToday($0.fireDate) }) {
print("\(reminders[indexOfFirstReminderWhichFiresToday]) fires today")
}
This will return the dates in today:
let todayDates = arrayOfDates.filter { Calendar.current.isDateInToday($0) }

Resources