Same Countdown in different TimeZone - Swift - swift

I have already create a countdown that's working fine on CEST time zone, but I want that will show the same correct time remaining in all the countries with different Time Zone.
Any idea on how can I manipulate the code?
// here we set the current date
let date = NSDate()
let calendar = Calendar.current
let components = calendar.dateComponents([.hour, .minute, .month, .year, .day], from: date as Date)
let currentDate = calendar.date(from: components)
let userCalendar = Calendar.current
// here we set the due date. When the timer is supposed to finish
let competitionDate = NSDateComponents()
competitionDate.year = year
competitionDate.month = month
competitionDate.day = day
competitionDate.hour = hour
competitionDate.minute = minute
let competitionDay = userCalendar.date(from: competitionDate as DateComponents)!
//here we change the seconds to hours,minutes and days
let competitionDayDifference = calendar.dateComponents([.day, .hour, .minute], from: currentDate!, to: competitionDay)
//finally, here we set the variable to our remaining time
let daysLeft = competitionDayDifference.day
let hoursLeft = competitionDayDifference.hour
let minutesLeft = competitionDayDifference.minute
print("day:", daysLeft ?? "N/A", "hour:", hoursLeft ?? "N/A", "minute:", minutesLeft ?? "N/A")

Your current code doesn't work because the competition day is not represented by a point in time (x seconds since 1970), but as a local date time (year, month, day, hour, minute etc) instead.
To represent the competition date as a point in time, you need to associate it with a timezone, which you haven't provided. You can provide one to the Calendar that you use to get the Date from the date components:
var userCalendar = Calendar.current
userCalendar.timeZone = TimeZone(identifier: "...")!
And then the competition date will be converted to the same point in time no matter what timezone the device is in.
Alternatively, set competitionDate.timeZone:
competitionDate.timeZone = TimeZone(identifier: "...")!

Related

How do I programatically determine the time (hours/minutes) and set them to 00/00 in Swift?

I am doing some date math and before doing so am trying to programatically adjust the time associated with a date based on its current value. In the code below I am able to set the hours and minutes to 00/00 but I have to know the offset and manually set the value. Below is my code and next to each print statement I have listed the value I am getting. Any assistance in pointing out the error I am making will be appreciated. I wonder if it is a timezone issue relative to GMT.
Chris
func AdjustDateTime(vooDate: Date) -> Date {
let date = vooDate
let _ = print("date")
let _ = print(date) // returns 2021-10-25 06:00:00 +000
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
let year = components.year
let month = components.month
let day = components.day
let hour = components.hour
let minute = components.minute
let _ = print("hour")
let _ = print(hour!) // returns 0 even though the date above say 06
let _ = print("minute")
let _ = print(minute!) // returns 0
var comps = DateComponents()
comps.year = year
comps.month = month
comps.day = day! + 1
comps.hour = -06 // setting manually, would like to do so programatically
comps.minute = 00
let returnDate: Date = Calendar.current.date(from: comps)!
let _ = print("Return Date")
let _ = print(returnDate) // returns 2021-10-26 00:00:00 +0000, which is what I want
return returnDate
}
Setting the time zone as indicated by Jacob was the key to solving the problem. In the code where I read in the JSON file I modified my dateFormatter to what's shown below. This returns a date object as shown below the code. Now I do not need to worry about the hours, since they are 0. From there it is easy to add 1 day with a function, shown below. Before doing my date math I make the same adjustments to a date in the future, i.e. timezone and locale, and I get the correct difference between the two dates which was the ultimate goal. Thank you for the assistance.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "en_US_POSIX") // added
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0) // added
2021-10-25 00:00:00 +0000
func AdjustDateTime(vooDate: Date) -> Date {
return Calendar.current.date(byAdding: .day, value: 1, to: vooDate)!
}

Calculate "Start" Time from "End" Time

I'm working to create a function that takes an input duration and an "end" time, and calculates a "start" time based on that criteria.
Example: if the "end" time is 5:00pm and the "duration" is 30 minutes, then the "start" time returned should be 4:30pm.
I'm getting lost in translating between Int/Date/String, so I may need to re-think my entire approach. So far I'm working with the following, which is just a take on this Stack Overflow post:
var userInputEventEndTime: String
var userInputEventDuration: Int
var userInputEventNeedsToStartTime: String
//Manipulate this function with the input parameters
func makeDate(hr: Int, min: Int, sec: Int) -> Date {
var calendar = Calendar(identifier: .gregorian)
let components = DateComponents(hour: hr, minute: min, second: sec)
let hour = calendar.component(.hour, from: calendar.date(from: components)!)
let minutes = calendar.component(.minute, from: calendar.date(from: components)!)
let seconds = calendar.component(.second, from: calendar.date(from: components)!)
return calendar.date(from: components)!
}
Should I be converting the input strings to DateComponents and then doing the math? If so, I'm not sure how to account for minutes converting to hours. Or just go a different direction altogether? Thanks!
The following uses DateComponents and Calendar to calculate the start time
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm a"
let calendar = Calendar.current
let dateComponents = DateComponents(calendar: calendar, minute: -userInputEventDuration)
if let endTime = dateFormatter.date(from: userInputEventEndTime),
let startTime = calendar.date(byAdding: dateComponents, to: endTime, wrappingComponents: false) {
userInputEventNeedsToStartTime = dateFormatter.string(from: startTime)
}
Here is the same solution written as a function with an example
func calculateStartTime(from endTime: String, duration: Int) -> String? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm a"
let calendar = Calendar.current
let dateComponents = DateComponents(calendar: calendar, minute: -duration)
if let time = dateFormatter.date(from: endTime),
let startTime = calendar.date(byAdding: dateComponents, to: time, wrappingComponents: false) {
return dateFormatter.string(from: startTime)
}
return nil
}
if let startTime = calculateStartTime(from: "6:00 PM", duration: 30) {
print("Event starts at \(startTime)")
}
Output
Event starts at 05:30 PM
To subtract components from the date, just add their negative values.

How to get UTC for date in midnigs in swift

Can somebody help me to get current UTC date time.
I am trying:
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let components = cal.components([.Day , .Month, .Year ], fromDate: NSDate())
let refDate = cal.dateFromComponents(components)
But I am getting 1/12/2017 23:00:00
This is seems UTC local time.
I want to get UTC for current date at midnight.
In database I save date as number of seconds but on server it is saved as 1/13/2017 00:00:00 and in swift I am getting 1/12/2017 23:00:00 so I can't get values as they are different I don't understand what I need to do to get same UTC.
In database I save date as long number of seconds in swift I am getting it by UInt64(floor(refDate!.timeIntervalSince1970)) but date is incorrect.
You need to set hour, minute and second property of NSDateComponents to 0
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
cal.timeZone = NSTimeZone(name: "UTC")!
let components = cal.components([.Day , .Month, .Year,.Hour, .Minute, .Second], fromDate: NSDate())
components.hour = 0
components.minute = 0
components.second = 0
let refDate = cal.dateFromComponents(components)
Or from iOS 8 you can also use startOfDayForDate
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
cal.timeZone = NSTimeZone(name: "UTC")!
let refDate = cal.startOfDayForDate(NSDate())
print(refDate)

How to fetch day, month and hour from NSDate in Swift

I have an NSDate object called reservationDate and I want to fetch day, month and hour from the Date. However, I'm getting wrong values. How can I get these values?
The value of the reservationDate object
reservationDate NSDate 2016-08-05 21:00:00 UTC
thus I expect to get 5 as a day and 21 as a hour however I'm receiving 6 as a day and 0 as a hour. Should I expect something else?
let unitFlags: NSCalendarUnit = [.Hour, .Day, .Month, .Year]
let components = NSCalendar.currentCalendar().components(unitFlags, fromDate: reservationDate)
let day = components.day
let hour = components.hour
You have not set Time zone. Please assign it "UTC".
NSCalendar.currentCalendar().timeZone = NSTimeZone(name: "UTC")!
Try to set timezone with Calendar object with UTC
let unitFlags: NSCalendarUnit = [.Hour, .Day, .Month, .Year]
let calendar = NSCalendar.currentCalendar()
calendar.timeZone = NSTimeZone(name: "UTC")!
let components = calendar.components(unitFlags, fromDate: NSDate())
let day = components.day
let hour = components.hour
let currentDate = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.FullStyle
var convertedDate = dateFormatter.stringFromDate(currentDate)
dateFormatter.dateFormat = "EEEE, MMMM dd, yyyy, HH:mm"
convertedDate = dateFormatter.stringFromDate(currentDate)

How to change the current day's hours and minutes in Swift?

If I create a Date() to get the current date and time, I want to create a new date from that but with different hour, minute, and zero seconds, what's the easiest way to do it using Swift? I've been finding so many examples with 'getting' but not 'setting'.
Be aware that for locales that uses Daylight Saving Times, on clock change days, some hours may not exist or they may occur twice. Both solutions below return a Date? and use force-unwrapping. You should handle possible nil in your app.
Swift 3+ and iOS 8 / OS X 10.9 or later
let date = Calendar.current.date(bySettingHour: 9, minute: 30, second: 0, of: Date())!
Swift 2
Use NSDateComponents / DateComponents:
let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let now = NSDate()
let components = gregorian.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: now)
// Change the time to 9:30:00 in your locale
components.hour = 9
components.minute = 30
components.second = 0
let date = gregorian.dateFromComponents(components)!
Note that if you call print(date), the printed time is in UTC. It's the same moment in time, just expressed in a different timezone from yours. Use a NSDateFormatter to convert it to your local time.
swift 3 date extension with timezone
extension Date {
public func setTime(hour: Int, min: Int, sec: Int, timeZoneAbbrev: String = "UTC") -> Date? {
let x: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
let cal = Calendar.current
var components = cal.dateComponents(x, from: self)
components.timeZone = TimeZone(abbreviation: timeZoneAbbrev)
components.hour = hour
components.minute = min
components.second = sec
return cal.date(from: components)
}
}
//Increase the day & hours in Swift
let dateformat = DateFormatter()
let timeformat = DateFormatter()
dateformat.dateStyle = .medium
timeformat.timeStyle = .medium
//Increase Day
let currentdate = Date()
let currentdateshow = dateformat.string(from: currentdate)
textfield2.text = currentdateshow
let myCurrentdate = dateformat.date(from: dateTimeString)!
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: myCurrentdate) // Increase 1 Day
let tomorrowday = dateformat.string(from: tomorrow!)
text3.text = tomorrowday
text3.isEnabled = false
//increase Time
let time = Date()
let currenttime = timeformat.string(from: time)
text4.text = currenttime
let mycurrenttime = timeformat.date(from: currenttime)!
let increasetime = Calendar.current.date(byAdding: .hour, value: 2, to: mycurrenttime) //increase 2 hrs.
let increasemytime = timeformat.string(from: increasetime!)
text5.text = increasemytime