Get current local time in UTC and set to Binary operator like >= or < - swift

Bear with me, I'm a newbie to iOS development; I'm currently trying to get the current time in UTC based on the device's local time, and set it in an if / else statement based on the whatever the current time in UTC is.
I've tried the below:
let UTCdate = Date()
if (UTCdate >= 13 && UTCdate < 23 {
// do something
}
It's giving me the error that "Binary operator '>=' cannot be applied to operands of type 'Date' and 'Int'
I know I'm doing something wrong, just don't know what. Apologies if this has already been asked. I google'd to the best of my abilities.

You need to extract the hour from your date. Date is a timestamp, not an hour. And you need to make sure you extract the hour in the UTC timezone and not locale time.
The following will do what you need:
// Create a calendar with the UTC timezone
var utcCal = Calendar(identifier: Calendar.current.identifier) // or hardcode .gregorian if appropriate
utcCal.timeZone = TimeZone(secondsFromGMT: 0)!
// The current date
let date = Date()
// Get the hour (it will be UTC hour)
let hour = utcCal.component(.hour, from: date)
if hour >= 13 && hour < 23 {
}
If you just use the current calendar to extra the hour from date you will get the hour in local time. That is the reason we created a new calendar specific to the UTC timezone (since that is your requirement).
Based on some comments you may not actually want UTC. Simply set the timeZone to whatever timezone you actually need.
If you want Chicago time, use:
utcCal.timeZone = TimeZone(identifier: "America/Chicago")!
And an alternate to creating your own calendar instance is to use:
let hour = Calendar.current.dateComponents(in: TimeZone(secondsFromGMT: 0)!, from: date).hour!
Again, use whatever timezone you need.

You said "I'm currently trying to get the current time in UTC based on the device's local time". You seem not to understand a key thing about Date objects in Cocoa. A Date is an instant in time, anywhere on the planet. It doesn't have a time zone. Internally it's represented as an offset from a moment in time that's expressed in UTC, known as the "epoch date", but that's an implementation detail. Imagine that when I capture a Date using the call Date(), I snap my fingers and the sound of the finger snap is heard all around the world at the same instant, without even speed-of-light delay. The finger snap is the moment that the call to Date() captures.
If I use the code let date = Date() I capture the current time all over the planet. A Date object doesn't have a specific time of day unless I convert it to a specific time zone. As others have suggested, the Calendar method dateComponents(in:from:) will let you extract components like the hour in a specific time zone from a Date, but you need to understand how all this works or you're going to get confused.
I suggest searching on the phrase "Calendrical Calculations" in the Xcode help system and reading that section of the docs. It's very helpful.

Related

Does the creation of a date object accept a parameter for a timezone?

To my understanding let date = Date() would create a date object with my current timezone. I've seen that there are certain functions where I would use a date formatter to then convert it into UTC time and add the offset to that time and then convert back into a date object but I'm wondering if there is a more elegant solution? And if not is there any other way to get the current time in another timezone in a date object without using the data formatter, as I require the calendar.component(.weekday, from: date) to find the date of the week.
If you look at the very first line on the documentation on Date, you can read the following:
A specific point in time, independent of any calendar or time zone.
So your two options when you want to deal with a local date are the DateTimeFormatter and Calendar

Get the local time of chosen timezone - Swift

I am creating a social media app. You can only post once every 24 hours, and I'm using it with firebase so all of the post' data goes to the firebase database.
When creating a post I have the variable Date, this is how you track if it's been 24 hours since the last post...
The only problem is that the user can just change the clock on their device and post as many times as they want. I need to get a date variable that is the local time of my timezone (EST) so I know that the data is accurate, but I'm not sure how to do it...
This is how I would usually get the current date:
let date = Date()
let currentTime = date.timeIntervalSince1970
So, I just need to get currentTime to be the current Eastern Standard Time (EST)
Thanks in advance!
Get the current timestamp form the firebase server and compare to the date from the last post
firebase.database.ServerValue.TIMESTAMP
Go here for reference firebase.database
for firestore
firebase.firestore.Timestamp.now()
Go here for reference firebase.firestore
If you want to make sure that 24 hours have passed, you need to compare the date in UTC, not in EST, UTC is a date without any time zone
and here
let date = Date()
let currentTime = date.timeIntervalSince1970
you have UTC timestamp
UPD: the fact of publication itself should be checked exclusively on the server, while the server should take its UTC time and check the time of the last publication from the database, before publishing.
If you are not trusting the device time, you could probably use an NTP client to get the date through an internet connection.
There are some implementations written in Swift like TrueTime and Kronos.
Both appears to use by default time.apple.com.
Their respective guides (on README files) seems to be pretty straightforward.
Example using TrueTime:
let client = TrueTimeClient()
client.start()
client.fetchIfNeeded { result in
switch result {
case let .success(referenceTime):
// Current date
let now = referenceTime.now()
client.pause()
case let .failure(error):
print("Error: \(error)")
}
}
Example using Kronos:
Clock.sync { date, offset in
// Current date
print(date)
}

Is it possible to specify an ISO Date with a timezone (i.e. GMT offset) but without a time?

I'm trying to see if you can specify a date with a timezone in ISO but without also specifying a time.
This may seem odd to ask about having a timezone without actually having a time, but technically a date represents a range between two times... the 24-hour period spanning from midnight to midnight, and that 'midnight' has to be in a timezone.
In our case, we have an API that wants to say 'Filter things on-or-before date X and on-or-after date Y' and we want the user to specify 'April 9th' (in their time zone) for both to get all things that happen on that day.
Of course we solve this by adding a day to the first date, then changing it to a pure 'before', but the front-end is required to do that math. We can't do it on the backend because having to send a date with a time means we would be sending April 9th at midnight, then on the backend adding a day to that, but what if someone passed in 4pm?
We could fail the date if it has a non-midnight time, but then we're back to why pass it in the first place.
So again, can you have a date with a timezone but not have a time component?
To decode ISO8601 dates only with year-month-day and time zone set the appropriate formatOptions of the ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withFullDate, .withTimeZone]
If by time zone you mean a UTC offset (as used with ISO 8601 dates with times), this is no problem. If by time zone you mean a true time zone with historic, present and known future offsets from UTC, including for example summer time/DST, like America/New_York or North American Eastern Time, then ISO 8601 does not support that, neither for dates with nor without time of day.
2020-04-25-04:00
This is perfectly valid ISO 8601 for April 25 this year at offset -04:00. So you may use it for representing the interval from 2020-04-25T00:00-04:00 (inclusive) to 2020-04-26T00:00-04:00 (exclusive). Which would then be equivalent to 2020-04-25T04:00Z to 2020-04-26T04:00Z (Z meaning UTC).
Java example code
I don’t know any Swift, so cannot tell you how to format or parse such a string in Swift. In Java formatting it is not bad. Example:
LocalDate date = LocalDate.of(2020, Month.APRIL, 25);
String isoOffsetDateString = date
.atStartOfDay(ZoneId.of("America/New_York"))
.format(DateTimeFormatter.ISO_OFFSET_DATE);
System.out.println(isoOffsetDateString);
Output:
2020-04-25-04:00
I am using Java’s built-in ISO_OFFSET_DATE formatter. The documentation informs us that this formnatter is:
The ISO date formatter that formats or parses a date with an offset,
such as '2011-12-03+01:00'.
Parsing the string and producing the start and end of the day takes a little more:
TemporalAccessor parsed
= DateTimeFormatter.ISO_OFFSET_DATE.parse(isoOffsetDateString);
Instant start = LocalDate.from(parsed)
.atStartOfDay(ZoneOffset.from(parsed))
.toInstant();
Instant end = start.plus(1, ChronoUnit.DAYS);
System.out.println("From " + start + " inclusive to " + end + " exclusive");
From 2020-04-25T04:00:00Z inclusive to 2020-04-26T04:00:00Z exclusive
I have opted to convert to Instant, the class for a moment in time independent of offset or time zone. Instants print in UTC, as the trailing Z on each says. In your Java code you may prefer not to do this conversion or to do a different conversion, all depending on circumstances.
Link
Documentation of DateTimeFormatter.ISO_OFFSET_DATE

Does Date() always init UTC date?

I'd like to know if Date() always init UTC date.
Example:
App is running in location UTC-8
Call Date() => date in UTC or UTC-8?
Thanks.
Date() initiates a single point in time, independent of any particular calendar system or time zone. Date values represent a time interval relative to an absolute reference date.
So the displayed value will be different depending on timezone, e.g.
01/01/2020T00:00:00 in UTC
will be presented as
31/12/2019T23:00:00 in UTC+1

How to get exactly real current date

I know you guys might be saying that this question is very common but actually I'm referring to the actual current date and time:
Let say today is 1st of August,12pm and no matter how the user change their phone date and time, I will still know today is 1st of August, 12pm...
Anyone know how can I do that?
You can get the real date and time from an NTP server, but this assumes that you have internet access.
If the user changes their phone date and time, then you will get that date and time... since NSDate gets its value from the iOS. If you want it to return the actual time per time zone, you will have to set up a small Web Service or something that returns the time for that particular time zone.
NSDate *currentDate = [NSDate date];
Now currentDate will have the current date & time when this code is executed.