Swift Get previous years datetime at GMT+08:00 timezone - ios

I need to get previous 5 years of GMT +08:00 timezone but I'm having trouble of getting the correct timezone.
let today = NSDate()
let gregorian = NSCalendar(calendarIdentifier: NSGregorianCalendar)
gregorian?.timeZone = NSTimeZone(forSecondsFromGMT: 60*60*8)
let offsetComponents = NSDateComponents()
offsetComponents.year = years
let nYearsDate: NSDate = gregorian!.dateByAddingComponents(offsetComponents, toDate: today, options: NSCalendarOptions(0))!
println("getNYearsDate: \(nYearsDate)")
I am getting 2010-07-23 11:44:47 +0000
instead of 2010-07-23 00:00:00 +0800
I need to get
2010-07-23 00:00:00 +0800 and 2010-07-23 23:59:59 +0800
is there anyway to achieve this in Swift and iOS 7.1 above?

You need to reset the time as well. Date periods are also best modeled with NSDateComponents.
// a little trick to get all calendar unit masks
let kAllCalendarUnits = NSCalendarUnit(rawValue: UInt.max)
// normalize the date
let components = NSCalendar.currentCalendar().components(
kAllCalendarUnits, fromDate: NSDate())
components.hour = 0
components.minute = 0
components.second = 0
let dateAtStartOfDay = NSCalendar.currentCalendar().dateFromComponents(components)!
// subtract 5 years
var period = NSDateComponents()
period.year = -5
let finalDate = NSCalendar.currentCalendar().dateByAddingComponents(period,
toDate: dateAtStartOfDay, options: [])!
Note that the method with date components will give you the correct day, regardless if the period contains one or two leap years.
The rest is just a question of how to display this date. This is done with NSDateFormatter. Eg.:
let formatter = NSDateFormatter()
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 60 * 60 * 8)
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss Z"
formatter.stringFromDate(finalDate)
// "2010-07-23 6:00:00 +0800"
In case you are wondering why it says "6:00" instead of "8:00": I ran this code with my machine set to GMT+1, plus summer time +1. Obviously, to get "0:00" you have to subtract the desired time difference again, but that would be 8 hours earlier in the GMT time zone.

Related

Converting the string to date giving different format [duplicate]

This question already has answers here:
Getting date from [NSDate date] off by a few hours
(3 answers)
Closed 3 years ago.
Converting from string to date and date to string time format is changing the original data.
Tried with dateComponents as well by giving the hour and minute
var calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour], from: calFrom)
calendar.timeZone = .current
// Specify date components
var dateComponents:DateComponents = calendar.dateComponents([.year, .month, .day, .hour], from: Date())
dateComponents.year = components.year
dateComponents.month = components.month
dateComponents.day = components.day
dateComponents.hour = 08//Cutomised hour
dateComponents.minute = 34//Cutomised Minutes
// Create date from components
let someDateTime = calendar.date(from: dateComponents)
print(someDateTime!)
Actual Output:
2019-04-02 03:04:00 +0000
Expected Output:
2019-04-02 08:34:00 +0000
I tried with below code as well. Converting the date to String and manually appending the hour and minutes to the string and converting back to the date.
let calFrom = Date()
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
var calFromDate = formatter.string(from: calFrom)
calFromDate = calFromDate + " 09" + ":30"
print(calFromDate)
//Output 02/04/2019 09:30
formatter.dateFormat = "dd/MM/yyyy hh:mm"
formatter.locale = Locale.current// set locale to reliable US_POSIX
let date1 = formatter.date(from: calFromDate)
print(date1!)
Actual Output:
2019-04-02 04:00:00 +0000
Expected Output:
02/04/2019 09:30
How to get the exact time that has given in the output?
Date used to update the hour and minute components has UTC timezone so calendar should also have the same timeZone as below,
calendar.timeZone = TimeZone(abbreviation: "UTC")!

Swift 4 : Set Different Date and Time

I know how to get local date and time, but what I want to do is getting the date and time from different places. For example, I want to find out what the time and date is in New York. How can i solve this simple problem?
Here is my code for local date and time :
let date = NSDate()
let calendar = Calendar.current
let components = calendar.dateComponents([.hour, .minute, .month, .year, .day, .second, .weekOfMonth], from: date as Date)
let currentDate = calendar.date(from: components)
I searched about it here, but i didn't find what i want and I'm still looking for the date libaries. If you know any source or sample to redirect me, I really appreciate that.
There are several different concepts involved here, and we need to understand (almost) all of them to get this right...
1) a Date (NSDate as was, in Swift) is an absolute point in time - it's slightly mis-named, because it has nothing to do with an actual date like 13th November 2017, because to get to that we need to define ...
2) a Calendar, because 13th November 2017 in the western Gregorian calendar could also be 23rd Safar 1439 in the Islamic calendar, or the 24th of Heshvan 5778 in the Hebrew calendar, or some other things in the many other calendars that iOS & MacOS support;
3) in turn Calendar changes not only what values are returned in the DateComponents that we have to use to unpack a Date + Calendar into days, months, years & eras (e.g. BC/AD), or even week number, etc..., but also some calendars might not have the same components as others;
4) time-of-day (as you know) depends on TimeZone, so the same absolute time can be one of many different times "o'clock" depending on where you are. It may also (as you can see in the example below) change the date as well as the "o'clock". This of course could be automatic (where you are) or set by the programmer;
5) further, we have DateFormatter (which is a convenience that wraps up DateComponents), because 13th November 2017 could be represented as 13/11/17 or 11/13/17 depending on whether you are British or American. We may also wish to choose whether we use text or numeric months, and, if displaying times, whether we want 12 hour or 24 hour format - all of these are covered by DateFormatter, but text representation may be "13e Novembre 2017" if you are French, which introduces the notion of
6) Locale, which can be set, like TimeZone, as being default (as chosen when you set up the device) or specified by the programmer.
The code you posted won't work, because all it does is takes a Date, transforms it through a Calendar to DateComponents (all good so far), but then recreates a Date from the components - all you will get is the original Date - the same absolute point in time.
What I believe from the question and your answers to questions in the comments is that you want a function that takes an absolute time (eg "now") aka a Date and displays it in a specific TimeZone. This works:
func timeComponents(date: Date, timeZone: TimeZone) -> DateComponents {
var calendar = Calendar.current
calendar.timeZone = timeZone
return calendar.dateComponents([.hour, .minute, .month, .year, .day, .second, .weekOfMonth], from: date)
}
let absTime: Date = Date() // Now
let edinburgh = TimeZone(abbreviation: "GMT")!
let newYork = TimeZone(abbreviation: "EST")!
let ec = timeComponents(date: absTime, timeZone: edinburgh)
let nycc = timeComponents(date: absTime, timeZone: newYork)
print(ec)// year: 2017 month: 11 day: 14 hour: 0 minute: 44 second: 10 weekOfMonth: 3 isLeapMonth: false
print(nycc) // year: 2017 month: 11 day: 13 hour: 19 minute: 44 second: 10 weekOfMonth: 3 isLeapMonth: false
... which I think answers the minimum of your question, but to finesse it, we need to move from DateComponents to DateFormatter
func timeString(date: Date, timeZone: TimeZone, timeStyle: DateFormatter.Style) -> String {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = timeZone
dateFormatter.dateStyle = .none
dateFormatter.timeStyle = timeStyle
return dateFormatter.string(from: date)
}
let es = timeString(date: absTime, timeZone: edinburgh, timeStyle: .full)
let nycs = timeString(date: absTime, timeZone: newYork, timeStyle: .full)
print(es) // 12:44:10 AM Greenwich Mean Time
print(nycs) // 7:44:10 PM Eastern Standard Time
You can go on, and start to use Locale, if you want to internationalise your app, but I'l leave that as an exercise!
p.s. These are not all of the concepts - see here
p.p.s. See also this answer and this answer (neither duplicates)
If you just want to format the date to a string, consider using a DateFormatter instead:
let date = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "America/New_York")
formatter.dateStyle = .long
formatter.timeStyle = .long
formatter.string(from: date)
If you want to get the date components and process them, use the dateComponents(in:from:) method.
let components = Calendar.current.dateComponents(in: TimeZone(identifier: "America/New_York")!, from: date)
If you don't know the time zone of the place you are searching for, you can use the CoreLocation's CLGeocoder and search on an address string. Then you can get the timezone for that place and translate that into the time you're looking for:
let geocoder = CLGeocoder()
geocoder.geocodeAddressString("New York, New York") { (placemarks, error) in
guard error == nil else {
print("Error")
print(error!.localizedDescription)
return
}
guard let placemarks = placemarks,
let place = placemarks.first else {
print("No results")
return
}
if let timeZone = place.timeZone {
print("TimeZone: \(timeZone.identifier)")
// TimeZone: America/New_York
//Ignore the time zone offset from this one, it will be the difference between the current time and the new york time
let dateInNewYork = Date().addingTimeInterval(TimeInterval.init(timeZone.secondsFromGMT()))
print(dateInNewYork)
// 2017-11-13 15:03:05 +0000
//Or
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: timeZone.identifier)
formatter.dateStyle = .long
formatter.timeStyle = .long
let formattedDateInNewYork = formatter.string(from: Date())
print(formattedDateInNewYork)
// November 13, 2017 at 3:03:05 PM EST
//Or
let components = Calendar.current.dateComponents(in: TimeZone(identifier: timeZone.identifier)!, from: Date())
print(components.date!)
// 2017-11-13 20:03:05 +0000
}
}

Calculating date and time based on user's timezone [duplicate]

This question already has answers here:
iOS: Convert UTC NSDate to local Timezone
(15 answers)
Closed 6 years ago.
I have a requirement in which I have a local DB full of dates from a particular timezone and I want to convert this date from that particular timezone to user's local timezone. The way I've implemented is that first I am always converting the DB date to UTC by adding the hours difference and then converting it to user local time zone by taking the time interval using
NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT
and adding it to the UTC date. I would like to know that is the approach fine because it worked till now on my limited testing. Also will it account for countries which has Day light saving currently active.
The complete code :
func calculateDate(model:EventModel) -> NSDate
{
let date = model.Date
let startTime = model.StartTime
let arrayForTime = startTime?.componentsSeparatedByString(":")
let arrayForDates = date?.componentsSeparatedByString("-")
let calender = NSCalendar(identifier:NSCalendarIdentifierGregorian)
let year = Int(arrayForDates![2])
let month = Int(arrayForDates![1])
let day = Int(arrayForDates![0])
let hour = Int(arrayForTime![0])! + 3 //UTC - 3 the local time
let minutes = Int(arrayForTime![1])
let dateComponents = NSDateComponents()
dateComponents.day = day!
dateComponents.month = month!
dateComponents.year = year!
dateComponents.hour = hour
dateComponents.minute = minutes!
dateComponents.second = 0
dateComponents.timeZone = NSTimeZone(name: "UTC")
let UTCDate = calender?.dateFromComponents(dateComponents)
let dateLocal = self.getLocalDate(UTCDate!)
return dateLocal
}
func getLocalDate(utcDate:NSDate) -> NSDate
{
let timeInterval = NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT)
let localdate = utcDate.dateByAddingTimeInterval(timeInterval)
return localdate
}
Previously I was using this but it was not returning the correct local date for Day light saving countries.
func getLocalDate(utcDate:NSDate) -> NSDate
{
let timeInterval = NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT)
// let timeZoneObj = NSTimeZone.localTimeZone()
let localdate = utcDate.dateByAddingTimeInterval(timeInterval)
// let isDayLightSavingOn = timeZoneObj.isDaylightSavingTimeForDate(localdate)
// if(isDayLightSavingOn == true)
// {
// let dayLightTimeInterval = timeZoneObj.daylightSavingTimeOffsetForDate(localdate)
// timeInterval -= dayLightTimeInterval
// }
// localdate = utcDate.dateByAddingTimeInterval(timeInterval)
return localdate
}
Thanks in advance. Cheers !
You don't "convert" the NSDate to a timezone. You simply create a string representation of the NSDate in the user's time zone using a NSDateFormatter. The timeZone of the NSDateFormatter defaults to the user's own timezone, so no adjustments are necessary when displaying it in the user's local timezone. For example:
let date = ... // let's imagine it was "2016-05-18 00:03:34 +0000"
let formatter = NSDateFormatter()
formatter.dateStyle = .LongStyle
formatter.timeStyle = .LongStyle
let userDateString = formatter.stringFromDate(date)
If the user was in GMT/UTC-7 timezone, for example, that would result in:
"May 17, 2016 at 5:03:34 PM PDT"
Clearly, change the dateStyle and timeStyle to format it however best for your user interface. But don't do any adjustments of NSDate objects at all, but rather just build a string representation in the user's own timezone.

Get tomorrow's date with Swift 2

I have this code which gives today's date in this formate M/dd/yy
let dateFormater = NSDateFormatter()
dateFormater.dateFormat = "M/dd/yy"
let todayDate = dateFormater.stringFromDate(NSDate())
How can I get the same thing but with next day's date please?
First, you get a NSDate for the day you need, in this example (one day from now is tomorrow):
var oneDayfromNow: Date? {
Calendar.current.date(byAdding: .day, value: 1, to: Date())
}
print(oneDayfromNow)
Then you convert it to your format as string (your case M/dd/yy):
if let oneDayfromNow {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "M/dd/yy"
let str = dateFormatter.string(from: oneDayfromNow)
print(str)
}
It's a bit complicated, but it's all things that you need to know anyway.
Why it's difficult: You would think that you could just take NSDate (timeIntervalSinceNow:24 * 60 * 60), adding one day to now. But when you turn on daylight savings time, then 11:30pm plus 24 hours is 00:30am two days later. When daylight savings time is turned off, then 00:30am plus 24 hours can be 11:30pm on the same day.
So you need to create an NSCalendar object, convert NSDate () into components, add one day to the components, convert back to an NSDate (all that gives you the same time on the next day, handling all special cases), and then format the result as you did now.
I finally used this code to fix it :
let dateFormater = NSDateFormatter()
dateFormater.dateFormat = "M/dd/yy"
let todayDate = dateFormater.stringFromDate(NSDate().dateByAddingTimeInterval(24 * 60 * 60))

How to make NSDate() print the current local time [duplicate]

This question already has answers here:
Converting NSString to NSDate (and back again)
(17 answers)
Get UTC time and local time from NSDate object
(10 answers)
Closed 7 years ago.
I have tried this in playgrounds (I show in comments what it's printed):
extension NSDate {
static func currentDate() -> NSDate {
let calendar = NSCalendar.currentCalendar()
calendar.timeZone = NSTimeZone.localTimeZone()
calendar.locale = NSLocale.currentLocale()
let components = calendar.components([.Year, .Month, .Day], fromDate: NSDate())
components.hour = 00
components.minute = 00
components.second = 00
return calendar.dateFromComponents(components)! // "Dec 29, 2015, 12:00 AM"
}
}
print(NSDate.currentDate()) // "2015-12-28 22:00:00 +0000
Anyone has an idea what is going on here ?
I just want the current date (year/month/day). I made this extension because I had problems with NSDate(), it was off by 2 hours (showing 11.24 am, instead of 1.24 pm)
The NSDate() in Swift and [NSDate date] in Objective-C both holds the UTC date. You can not change it behaviour.
However you can create a formatter and convert to desired locale and date format and store the date as string value.
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = /*your desired format*/
let date = dateFormatter.dateFromString(/*your date string*/)

Resources