Check if local time is after midnight in another timezone - swift

I want to check if my local time is after midnight in another time zone.
Specifically, if right now where I am at is 11 PM Saturday, or 1 AM Sunday local time, I want to see if it is the start of a new week in Central Time (after 12 AM Sunday).

You can use Calendar's dateComponents(in: TimeZone, from: Date) to check the time and date in another timezone. For your specific application:
// create current date, central time zone, and get the current calendar
let now = Date()
let centralTimeZone = TimeZone(abbreviation: "CST")!
let calendar = Calendar.current
let components = calendar.dateComponents(in: centralTimeZone, from: now)
if components.weekday == 1 {
print("It is Sunday in Central Standard Time.")
} else {
print("It is not Sunday in Central Standard Time.")
}
What you're doing there is asking the current calendar to give you a full set of DateComponents in the specified timezone. Then components.weekday gives the day of the week as an Int, starting with 1 for Sunday in the Gregorian calendar.
If you want to know more generally if it's "tomorrow" somewhere, here's a simple method:
func isItTomorrow(in zone: TimeZone) -> Bool {
var calendarInZone = Calendar(identifier: Calendar.current.identifier)
calendarInZone.timeZone = TimeZone(abbreviation: "CST")!
return calendarInZone.isDateInTomorrow(Date())
}
if isItTomorrow(in: centralTimeZone) {
print("It is tomorrow.")
} else {
print("It is not tomorrow.")
}
isItTomorrow(in: TimeZone) creates a new calendar of the same type as the current calendar (presumably .gregorian, but you never know) and sets its timezone to the desired one. Then it uses the neat built-in Calendar method .isDateInTomorrow() to check if the current time is "tomorrow" in the target timezone.
There are lots of other ways to do it, and depending on your specific need there may be a built-in method that will save you a lot of work, so it's well worth reading through the docs on Calendar and DateComponents to see what's available.

Related

Current date brings back time as well

I'm trying to get the date only, I wrote this:
func getCurrentDate() -> Date {
dateFormatter.dateFormat = "dd.MM.yyyy"
let result = dateFormatter.string(from: date)
print(result)
let date = dateFormatter.date(from: result)
return date!
}
printing 'result' I get:
12.07.2019
which is what I need, but converting it to Date type and printing it results in:
2019-07-11 21:00:00 +0000
Why does that happen and how can I fix it ?
Date was very unfortunately named. It has nothing to do with dates. It represents an instant in time. An instant that all observers (ignoring details like Relativity) would agree on. It isn't "a day on the calendar." It's a point in time, independent of any calendar.
The fact that it prints out in a "calendar-like" way is just a convenience for debugging.
If you want "a specific day on a calendar" then the tools you want is DateComponents and Calendar, not Date:
func currentDay() -> DateComponents {
return Calendar.current.dateComponents([.year, .month, .day], from: Date())
}
Keep in mind that the user's current calendar may not be Gregorian. If you require the Gregorian calendar, you need to say so:
func currentDay() -> DateComponents {
return Calendar(identifier: .gregorian).dateComponents([.year, .month, .day],
from: Date())
}
The Gregorian calendar is the one where the current year is 2019. In the Hebrew calendar, it's 5779. In the Buddhist calendar, it's 2562. In the Islamic calendar, it's 1440. There is no one "correct" calendar, which is why you need to provide one.
Reading your comments, it's possible you mean "the start of 'today' using the current calendar." If that's what you want, then you would use this:
func currentDay() -> Date {
return Calendar.current.startOfDay(for: Date())
}
(Or use the Gregorian calendar if needed, though I don't believe any supported calendar disagrees about what the start of the day is.)

How to find midnight for a given Date in Swift

I creating an itinerary generation app where the user is required to enter the dates of his/her trip. The only problem is, using UIDatePicker the dates are always given as the current time for a given day/month/year.
In a separate file I've extended Date class to try and write a simple method that will return midnight for a given date.
First I tried
var midnight:Date{
let cal = Calendar(identifier: .gregorian)
return cal.startOfDay(for: self)
}
However this always gave me either 04:00 or 05:00 depending on daylights savings, which gave me the idea that I should simply remove 4 or 5 hours depending on daylight savings, and so I created the following methods:
var timezone:TimeZone{
return TimeZone.current
}
///Returns the first instance of the date, e.g. 2018-02-26 00:00:00
var trueMidnight:Date{
let cal = Calendar(identifier: .gregorian)
let midnight = cal.startOfDay(for: self)
let secondsFromGMT = TimeZone.current.secondsFromGMT()
print("Daylight savings? \(daylightSavings)")
return midnight.addingTimeInterval(Double(secondsFromGMT))
}
///If this var returns true, then daylight savings time is active and an hour of daylight is gained (during the summer).
var isDaylightSavings:Bool{
return timezone.daylightSavingTimeOffset(for: self) == 0 ? false : true
}
var daylightSavings:Double{
return isDaylightSavings ? 3600.0 : 0.0
}
However these methods sometimes return midnight, 23:00, or even 22:00 the previous day.
I'm a relatively inexperienced programmer so I feel like I'm lacking a basic understanding for the date class or missing a large concept. Why is it so difficult for me to simply find midnight on a given date?
I even forsook the idea of returning midnight and tried to just find noon on a given day with the code:
var noon:Date{
let gregorian = Calendar(identifier: .gregorian)
var components = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self)
components.hour = 12
components.minute = 0
components.second = 0
return gregorian.date(from: components)!
}
But this returns 16:00 or 17:00 as opposed to noon. Any help would be appreciated.
When you print a date, it is printed in UTC time. So when you print your Dates, they differ from your local time by 4/5 hours.
If you use the following code instead
print(yourDate.description(with: .current))
Where yourDate is your date, it will be in the correct time zone.
You're confused.
If you use
print(Date())
You will get a date in UTC. If you're in the UTC+5 time zone, that date will be 5 hours greater than your local time. Thus if you try to display midnight local time in UTC, it will show up as 5:00 AM in UTC.
Try this:
extension Date {
func localString(dateStyle: DateFormatter.Style = .medium,
timeStyle: DateFormatter.Style = .medium) -> String {
return DateFormatter.localizedString(
from: self,
dateStyle: dateStyle,
timeStyle: timeStyle)
}
var midnight:Date{
let cal = Calendar(identifier: .gregorian)
return cal.startOfDay(for: self)
}
}
print("Tonight at midnight is " + Date().midnight.localString())
That code uses a function localString() that takes advantage of a DateFormatter method localizedString(from:dateStyle:timeStyle:) that converts a Date to a string in the current locale (which includes the local time zone.
I suggest adding that extension to your apps.

Need simple way to compare a time string ONLY to the current dates time value

Say time string value is "7:00 AM" call it reminder time.
Now all I need to do is compare this time with the current dates time say its "9:00 AM" if reminder time is later than current time - return true else false. This is the format "h:mm a" for date formatters.
Simple right? It should be but I have burned too much time on this. I can get hour and minute values but when the AM/PM is considered it gets harder.
I just want to compare two time values and determine if the first is later or after the second one. The date is always today or current date so I only care about the time part of the date. Of course you have to convert to dates to do the comparison but current date is easy to get however date from "7:00 AM" string does not seem to work right in comparisons.
Anyone have a function to do this?
Thanks.
the approach would be lets date the Date() object from your current time object so you will get
default date + your time = 2000-01-01 00:00:00 +your time (7.00 AM or 9.00 PM)
now we will get the current time from today only, in same format. (Only time)
it will be something like 3.56 PM
now again we will convert this 3.56 PM to Date() with default date as prev. so now we will have two date time object with same Date(2000-01-01) and respective times.
2000-01-01 7:00:00 => this will your 7.00 AM with default date
2000-01-01 15:56:00 => this will be current time with default date
now we will compare two date object.
Check the fiddle Fiddle
func CompareMyTimeInString(myTime:String)->Bool
{
// create the formatter - we are expecting only "hh:mm a" format
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm a"
dateFormatter.locale = Locale.init(identifier: "en_GB")
// default date with my time
var dt_MyTime = dateFormatter.date(from: yourTime)!
// current time in same format as string "hh:mm a"
var currentTimString = dateFormatter.string(from: Date());
print("Current Time is - "+currentTimString);
// current time with default date.
var dt_CurrentTime = dateFormatter.date(from: currentTimString)!
// now just compare two date objects :)
return dt_MyTime > dt_CurrentTime;
}
// then call it like
var yourTime = "7.00 AM"
var isDue = CompareMyTimeInString(myTime:yourTime);
print(isDue);
My solution was as follows.
private func ReminderAfterCurrentTime(reminderTimeString: String) -> Bool {
//Compare the two time strings and if reminderTimeString is later than current time string
//return true since Reminder is after current time.
//Get the current date and time
let currentDateTime = Date()
// Create calendar object
let calendar = NSCalendar.current
// Get current date hour and minute values for comparison.
let currentHourValue = Int(calendar.component(.hour, from: currentDateTime))
let currentMinuteValue = Int(calendar.component(.minute, from: currentDateTime))
//Now get a date from the time string passed in so we can get just the hours and minutes to compare
let dateformatter = DateFormatter()
dateformatter.dateStyle = DateFormatter.Style.none
dateformatter.timeStyle = DateFormatter.Style.short
//Now get the date using formatter.
let reminderDateTime = dateformatter.date(from: reminderTimeString)
print("reminderDateTime = \(reminderDateTime)")
//Get reminder hour and minute for comparison.
let reminderHourValue = Int(calendar.component(.hour, from: reminderDateTime!))
let reminderMinuteValue = Int(calendar.component(.minute, from: reminderDateTime!))
print("currentHourValue = \(currentHourValue)")
print("currentMinuteValue = \(currentMinuteValue)")
print("reminderHourValue = \(reminderHourValue)")
print("reminderMinuteValue = \(reminderMinuteValue)")
//This works due to 24 hour clock. Thus AM/PM is already taken into account.
if currentHourValue < reminderHourValue {
return true
}
//Check for same hour then use minutes
if currentHourValue == reminderHourValue {
if currentMinuteValue < reminderMinuteValue {
return true
}
}
//Otherwise return false
return false
}

Swift 3 - Time Part of Date And Different Timezones

I am having an issue with a date string received from a REST web service and how that is being represented in Swift in different timezones. I have just been able to reproduce this issue, so I am going to relate this specific example.
The information I am getting from the web service is a date-time string and a timezone identifier. In this case, the system is in the America/New_York or Eastern US timezone. I created a playground where I have the following code
let dateFormatString = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
let easternTimeZone = "America/New_York"
let serverDate = "2017-03-01T00:00:00-05:00"
I have a method that takes the date string and the timezone identifier and creates a Date object as follows
func dateForDateString(dateString: String, timeZone: String) -> Date?
{
let formatter = DateFormatter()
if timeZone != ""
{
formatter.timeZone = TimeZone(identifier: timeZone)
}
formatter.dateFormat = dateFormatString
return formatter.date(from: dateString)
}
When I call this method with what's returned from the web service
let easternDate = dateForDateString(dateString: serverDate, timeZone: easternTimeZone)
print("\(easternDate)")
The print statement outputs Optional(2017-03-01 05:00:00 +0000) which is expected. No problems yet. The problem happens when the device is in a different timezone and for the sake of this example, I am testing with Pacific time. In the playground, the easternTime variable shows as Feb 28, 2017, 9:00 PM. Again, not unexpected.
The date is going to be stored in a Firebase database and I don't care about the time at all. So I end up using the Calendar method startOfDay as follows
let myDate = Calendar.current.startOfDay(for: ed)
as you may expect, this returns the Date Feb 28, 2017, 12:00 AM. Obviously not what I want to store in Firebase. The bottom line is that I need the date to be in the timezone the web service returned.
UPDATE
As mentioned in the comments, I also tried to create a Calendar instance and set it's timeZone property to a TimeZone with the identifier received from the server. The code looks like this
var easternCal = Calendar(identifier: .gregorian)
if let etz = TimeZone(identifier: easternTimeZone)
{
easternCal.timeZone = etz
}
if let ed = easternDate
{
let convertedDate = dateToTimeZone(date: ed, toTimezone: easternTimeZone)
let currentCalDate = Calendar.current.startOfDay(for: ed)
let myDate = easternCal.startOfDay(for: ed)
print("\(myDate)")
}
Last night, I could have sworn this didn't work, but when I try it now in the playground, it appears to be working just fine. currentCalDate is the date I don't want, Feb 28, 2017, 12:00 AM since it is using the user's Calendar that has the Pacific timezone set. myDate is correctly showing as Feb 28, 2017, 9:00 PM, which is printing as 2017-03-01 05:00:00 +0000, what I have wanted all along.
I think this one is solved.
As mentioned in the update to my question, creating a Calendar instance and setting the timeZone property to the one returned from the back-end solved my problem.

Is there a daylight savings check in Swift?

I need to check to see if the current date is during daylight savings time. In pseudocode that would be like this:
let date = NSDate()
if date.isDaylightSavingsTime {
print("Success")
}
I haven't been able to find the solution to this anywhere on the internet.
An NSDate alone represents an absolute point in time.
To decide if a date is during daylight savings time or not
it needs to be interpreted in the context of a time zone.
Therefore you'll find that method in the NSTimeZone class and not
in the NSDate class. Example:
let date = NSDate()
let tz = NSTimeZone.localTimeZone()
if tz.isDaylightSavingTimeForDate(date) {
}
Update for Swift 3/4:
let date = Date()
let tz = TimeZone.current
if tz.isDaylightSavingTime(for: date) {
print("Summertime, and the livin' is easy ... 🎶")
}
Swift 4.0 or later
You can check a date isDaylightSavingTime in two ways by time zone identifier or abbreviation.
let timeZone = TimeZone(identifier: "America/New_York")!
if timeZone.isDaylightSavingTime(for: Date()) {
print("Yes, daylight saving time at a given date")
}
let timeZone = TimeZone(abbreviation: "EST")!
if timeZone.isDaylightSavingTime(for: Date()) {
print("Yes, daylight saving time at a given date")
}