Getting the Current Date in a Specific Time Zone - swift

I am trying to get the current date in a time zone selected by the user, but I can't get anything other than the current date despite using functions from other answers on stackoverflow. What I used is this:
func dateIn(timeZone: TimeZone) -> Date {
let now = Date()
var calendar = Calendar.current
calendar.timeZone = timeZone
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: now)
let date = calendar.date(from: components) ?? Date()
return date
}
I would really appreciate it if someone could help me understand why I'm not getting the date in the time zone although I changed the time zone of calendar to that time zone.

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.

Joining separated Date and Hour to create a single Date() Object

I have this app written in swift where I get a future date and a future hour (As Unix Timestamp) separately and I want to turned them into one Date() Object so I can converted to Unix Timestamp.
If you now another way to converted directly to Unix Timestamp feel free to post.
This may give you some ideas on how to accomplish what you want:
let calendar = Calendar.current
let currentDate = Date()
// Random future date, 1 month from now
let futureDate = calendar.date(byAdding: .month, value: 1, to: currentDate)!
let futureDateComponents = calendar.dateComponents([.year, .month, .day], from: futureDate)
// Random hour
let futureHour = 2
// Use your future date and your future hour to set the components for the new date to be created
var newDateComponents = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: currentDate)
newDateComponents.year = futureDateComponents.year
newDateComponents.month = futureDateComponents.month
newDateComponents.day = futureDateComponents.day
newDateComponents.hour = futureHour
newDateComponents.minute = 0
newDateComponents.second = 0
// Create a new date from components
let newDate = calendar.date(from: newDateComponents)!
// Convert new date to unix time format
let unixTime = newDate.timeIntervalSince1970
print(newDate) // 2018-03-06 02:00:00 +0000
print(unixTime) // 1520301600.0
Note that in a real project you should avoid force unwrapping (i.e. using '!').
If you have a date string in the form of dd-MM-yyyy, you can convert that to a Date object like so:
let string = "02-06-2018"
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
formatter.locale = Locale(identifier: "en_US_POSIX") // this is only needed if string is always gregorian but you don't know what locale the device is using
guard let date = formatter.date(from: string) else {
// handle error however you'd like
return
}
Or, if you already have a Date object, then you don't need the above. But regardless, once you have a Date, you can then get a Date by setting the hour, minute, and second as follows:
let hour = 14 // 2pm
guard let result = Calendar.current.date(bySettingHour: hour, minute: 0, second: 0, of: date) else {
// handle error however you'd like
return
}

Take a certain amount of days off the current date and print with certain date format

How would I take a certain amount of days (take away one day) off the current date and print with certain date format to the console.
I'm currently using:
print((Calendar.current as NSCalendar).date(byAdding: .day, value: -1, to: Date(), options: [])!)
Which prints the date and time as:
yyyy-MM-dd HH:MM:SS +0000
But I want it to print like:
dd-MM-yyyy
Is this at all possible?
It's best to break that into a few more easily readable/maintainable lines. First, calculate the date you want, then apply a date formatter.
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
print(dateFormatter.stringFromDate(yesterday))
swift 3.0 version
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
if let yesterday = yesterday {
print(dateFormatter.string(from: yesterday))
}else{
print("Date incorrectly manipulated")
}
You shouldn't use fixed format for Date format strings. Because you might have users from around the world and they don't see dates in the same way.
Rather you should use template format. You just specify which components you want to show and their order like:
let dateFormatter = DateFormatter()
// dateFormatter.locale = Locale(identifier: "bn-BD") // Enable this line only at the time of your debugging/testing
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ddMMyyyy",
options: 0,
locale: dateFormatter.locale)
let date = Calendar.current.date(byAdding: .day, value: -1, to: Date())
if let date = date {
let dateString = dateFormatter.string(from: date)
print(dateString)
}
You shouldn't set your locale by yourself. It's done by the
framework. You should only set your locale manually only at the time
of testing your app.
In the above example I'm using Locale as "bn-BD" which means Bangla in Bangladesh. You can find your a list of locales here

Why does Date formatter returns date correctly but time is showing as 00:00:00 when converting string to NSDate

I have a function where i have to retrieve a date from my own sqlite db of app. I have saved it using the formatter
My work flow
1..Save a date to db on Application did enter background(Saved as String)
2..When application become foreground again i make a date instance at that point of time too. Now i have two date's.
3..Convert both dates to correct format and get the seconds difference.
Convert from date to String-->
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.Z"
let myString = formatter.stringFromDate(NSDate()) // i get value"2017-05-18 16:49:38.+0530"
But when i reconvert it to NSDate(I Mean when i convert this to string again)-->
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.Z"
let lastloginDate=formatter.dateFromString(lastLogin) // i get value(Converting back to string \n for checking as the time difference was zero ) 2017-05-18 00:00:00.+0530
I want to compare two dates like a session out service , I do this by getting the calendar components difference of minute. However since its coming like this, the difference his always zero .
let myString1 = formatter.stringFromDate(date1)
let myString2 = formatter.stringFromDate(date2)
print("DATE 1\(myString1) DATE 2 \(myString2)")
let components = calendar.components(flags, fromDate: date2, toDate: date1, options: [])
let diff = components.second
print("Diffrence is \(diff)") // Always zero 😱
Why is this?
Try this one.
let myString1 = formatter.stringFromDate(date1)
let myString2 = formatter.stringFromDate(date2)
print("DATE 1\(myString1) DATE 2 \(myString2)")
let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: myString1, toDate: myString2, options: [])
let diff = components.second
print("Difference is \(diff)")