Get the local time of chosen timezone - Swift - 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)
}

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

Limiting functionality usage per month in Swift

There are a lot of apps that allow the user to use a functionality a certain number of times per month. And when the quota is reached that functionality is blocked till the end of the month.
I am trying to do the same thing and I seem to have run into a bit of a problem.
struct Data{
var text:String
var date:Date
}
var array : [Data] = [
Data(text: "Cars", date: Date()),
Data(text: "Bikes", date: Date()),
Data(text: "Trucks", date: Date())
]
func countForCurrentMonth(date: Date) -> Int{
let currentMonth = Calendar.current.component(.month, from: date)
print(currentMonth)
var datesArray = [Int]()
for item in array{
let month = Calendar.current.component(.month, from: item.date)
if month == currentMonth{
datesArray.append(month)
}
}
let itemCount = datesArray.count
return itemCount
}
func addItem(){
if countForCurrentMonth(date:Date()) > 120{
//functionality locked
print("subscribe to unlock")
}else{
//allowed
print("allowed")
}
}
The problem is here, the date property is compared with Date() which gives the users system date. As the users system date can be manually set, one could easily by bypass this limitation.
So my question is, how can I implement the same thing without using the system date and which doesn't require an internet connection.
One of the things that I tried was keeping a stored date on the device and every time the user opens the app it checks the system date and if it's not equal to the stored date incrementing the day count and replacing the stored date with the new date. However, this would only work if the user opens the app everyday of the month.
I don't think that there is a proper solution for this without an internet connection but you cloud also save the latest registered date your app has been used with. This way you could check if the current date is earlier and lock your app for instance and try to fetch the correct timestamp online, if possible.
But it may be possible this leads to other issues when the user travels and changes his timezone for example but generally this solution should work.
One option would be to store the date and have it be a crucial component. That way if a user was cheating, when compared to other users the date would be too far in the future to count in the app against the competition. Then you would just store the latest date and any earlier date would invalid the session or lock the progress of the app. For instance you could say apply changes to the user account if current date < item date. This could be a problem if you update all users every few seconds. But, in that case you'd probably be online. In this case it seems you want to limit by month though. So even if the user applied 120 changes this month and another 120 changes next month, the changes would only be valid in that next month. So they still get the number of changes applied in that month. Or the first 120 of them. Also, you may want to check the year while you're looking for valid dates.

dayjs - how to create an ISO datetime string in a different timezone?

I am building an browser-based application where the user sets the timezone of their application, e.g. "America/New_York". I have a part of the application that allows users to set reminders and I want the user to specify that they want, for example, to set a reminder for 28th Jan 2020 at 9am in their timezone. This should work such that it they are on holiday in London and used the application to set this reminder, displaying this reminder would still always be in the New York timezone. I store the dates as UTC in the applications database and when converting this back show the user will display it according to their timezone.
I have tried this method in Codesandbox, to convert the date to UTC to store in the database:
const dateInNewYork = dayjs("2020-01-28 09:00:00", { timeZone: "America/New_York" }).toISOString();
// displays as 2020-03-29T11:00:00.000Z - shouldn't this be 2020-01-28T14:00:00.000Z ?
What am I doing wrong here?
let timeSt = dayjs(time).unix()* 1000;
timeSt += 60*60*1000*8 //8 is means china beijing time.
let whatYouNeed = dayjs(timeSt).format("YYYY-MM-DD HH:mm");

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

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.

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.