NSDateFormatter return wrong date + Swift - swift

Code :
let dateString = "2016-04-02"
var formatter: NSDateFormatter = NSDateFormatter()
formatter.timeZone = NSTimeZone(abbreviation: "GMT +3:00")
formatter.dateFormat = "yyyy-MM-dd"
println("dateString: \(dateString)")
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let date = formatter.dateFromString(dateString)
println("date: \(date)")
formatter.dateFormat = "yyyy-MM-dd"
let formattedDateString = formatter.stringFromDate(date!)
println("formattedDateString: \(formattedDateString)")
Output :
dateString: 2016-04-02
date: Optional(2016-04-01 21:00:00 +0000)
formattedDateString: 2016-04-02
2016-04-01 21:00:00 +0000
I am trying to convert a string to NSDate datatype but not getting correct value. I have tried many solutions but its not returning correct value. I need it in yyyy-MM-dd format (2016-04-02) same as my input "2016-04-02". If someone can help would be really apriciated. Thanks in advance

I had the same problem and i this worked for me
You need to set the time zone
formatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00")

When you convert from string to NSDate, if you do not set the timezone to the formatter, you will get the NSDate of a date in your local time zone. I suppose that your time zone is GMT+3 .
Then, when you show the value of 'date' (using println, NSLog but not NSDateFormatter), without setting the time zone, you will get GMT+0 time. That why you got 3h later.
Depend on how to use NSDateFormatter, you will have the date string as you want. In your case, It returns what you want, doesn't it?
Remember that NSDate presents a moment of time.
let dateString = "2016-04-02"
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
println("dateString: \(dateString)")
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let date = formatter.dateFromString(dateString) //without specify timezone, your dateString "2016-04-02" is your local time (GMT-3),
//means it's 2016-04-02 00:00:000 at GMT+0. That is the value that NSDate holds.
println("date: \(date)") //that why it show 2016-04-01 21:00:000, but not 2016-04-02 00:00:000
formatter.dateFormat = "yyyy-MM-dd"
let formattedDateString = formatter.stringFromDate(date!)
println("formattedDateString: \(formattedDateString)")

Your date is perfectly good. :-) No pun intended.
I will elaborate more on what #HoaParis has answered.
First of all NSDate represents a moment in time. It is not a date time value at the given place. So NSDate representing midnight in Greenwich will be 5:30 in morning in India.
Now coming to your question. When you give a date format with out time the formatter will assume it to be mid night. Also if there is not timezone mentioned it will take the current time zone.
So '2016-04-02' represents '2016-04-02, 00:00:00' at your time zone. Your timezone is GMT+3 that means when it is midnight at your place it is still 21:00:00 hours of previous day at Greenwich i.e. UK.
As we discussed NSDate is a moment in time to the same NSDate object represents these two seemingly different times but in reality they are the same time moment.
When you print the date by default it will print the date with respect to GMT and not your time zone i.e 2016-04-01, 21:00:00. The formatter will take into account your time zone and make it '2016-04-02'

let dateFormatter = DateFormatter()
//Your current Date Format
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let finaldate = dateFormatter.date(from:"Your String")
//Your changing Date Format
dateFormatter.dateFormat = "MMM-dd"
let second = dateFormatter.string(from: finaldate!)

Related

How to convert "Hours:Minutes:Seconds AM/PM"(UTC timezone) to the user's time zone in the format of "Hours:Minutes AM/PM" in Swift?

The input string will always be in the Hours:Minutes:Seconds AM/PM format, and it will always be in the UTC Timezone (The string represents the sunrise time where the user is, but only in UTC). A few examples are:
10:3:30 AM,
2:40:01 PM,
12:0:04 AM
I want to convert the time to the user's timezone and then get rid of the seconds component, so that it is just "Hours:Minutes AM/PM"
So far, I think I can use
var localTimeZoneAbbreviation: String { return TimeZone.current.abbreviation() ?? "" }
to get the user's current timezone, but I still don't know how to convert the string to that timezone. Any suggestions?
Use DateFormatter. One instance to convert from your UTC time to a Date and another to convert from that Date to a localized String.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX") // set locale before format; good to use this locale for fixed date formats
formatter.dateFormat = "h:m:ss a"
formatter.timeZone = TimeZone(abbreviation: "UTC")
let date = formatter.date(from: "10:3:30 AM")! // whichever input string you have
let localFormatter = DateFormatter() // time zone and locale default to system's
localFormatter.dateFormat = "hh:mm a" // if you don't want a zero padding single digits then use "h:m a"
let string = localFormatter.string(from: date)
Note the day/month/year will implicitly default to the default for the system, (I'm seeing January 1 2000) but you can presumably ignore that.

Swift UTC TimeZone is not UTC

I have a question about Swift type TimeZone.
I need to get a UTC0 time zone to format my Date object. I'm creating TimeZone object like this.
let utcTimeZone = TimeZone(abbreviation: "UTC")
But when created this object gives me GMT0 time zone. Is this possible to get UTC0 time zone in Swift? Also what is the difference between GMT (fixed) and GMT (GMT) offset 0 in playground?
Xcode 10.3 Playground
Technically, there are really subtle differences between UTC and GMT (GMT could mean UT1), but the designers of the API thought they are practically the same (which they are), so they made this true:
TimeZone(identifier: "UTC") == TimeZone(identifier: "GMT")
They both represent a timezone with a constant offset of 0.
If you just want to show the letters "UTC" in some output text, use a DateFormatter:
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss 'UTC'"
print(formatter.string(from: Date()))
Or better yet, use a ISO8601DateFormatter, which adds a Z to the end of the date to indicate that the date time is in UTC:
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(identifier: "UTC")
print(formatter.string(from: Date()))
Also what is the difference between GMT (fixed) and GMT (GMT) offset 0 in playground?
The former comes from the Swift TimeZone class, and the latter comes from the Objective-C NSTimeZone class. One is the bridged version of the other. From the docs of NSTimeZone,
use NSTimeZone when you need reference semantics or other Foundation-specific behavior.
I've been there, according to google
There is no time difference between Coordinated Universal Time and Greenwich Mean Time
In other words, GMT is (basically) UTC, so you already have it!
offset 0 is referring to the timezones offset from UTC/GMT, which is 0, and would be potentially something like 240 if you were in EST (depending on if it's in minutes, hours, milliseconds etc.).
fixed on your second line means it's GMT and the offset data is potentially immutable. I wouldn't know without the playground open but I'd try changing the timezone after instancing that and see how if the offset can be changed post assignment.
You can use this instead of UTC, in some device only setting UTC not working
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date = dateFormatter.date(from: "2020-01-23T11:55:00.000Z")

Swift - NSDate - remove part of date

I have a date in following format 2015-02-22T20:58:16+0000
In order to convert it to NSDate I found following solution
var df = NSDateFormatter()
df.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ"
var date = df.dateFromString(myDate)
df.dateFormat = "eee MMM dd yyyy"
var dateStr = df.stringFromDate(date!)
But I want to remove +0000 from date. I tried to remove ZZZZm but app crashes.
How can I remove extra +0000 digits ?
You ask:
How can I remove extra +0000 digits?
I'm not sure what you mean, because the resulting dateStr does have the +0000 removed.
But let's step back and consider the right way to parse a date string in the format of 2015-02-22T20:58:16+0000. You should use a locale of en_US_POSIX as described in Apple Technical Q&A 1480:
let myDate = "2015-02-22T20:58:16+0000"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let date = dateFormatter.dateFromString(myDate)
When you then want to format that for the end user, reset the locale back to currentLocale:
dateFormatter.locale = NSLocale.currentLocale()
dateFormatter.dateFormat = "eee MMM dd yyyy"
let dateStr = dateFormatter.stringFromDate(date!)
The dateStr then becomes:
Sun Feb 22 2015
Or, perhaps better, for better localization behavior, use dateFormatFromTemplate:
let locale = NSLocale.currentLocale()
dateFormatter.locale = locale
dateFormatter.dateFormat = NSDateFormatter.dateFormatFromTemplate("eeeMMMdyyyy", options: 0, locale: locale)
let dateStr = dateFormatter.stringFromDate(date!)
In the US, it will appear like above, but in England it will appear as:
Sun, 22 Feb 2015
Or use one of the standard dateStyle values if that works for you. But I'd generally advise against using a hard-coded dateFormat, but rather use a format that honors the end-user's localization settings.
I wouldn't recommend removing time zone when you're parsing results. But if all you want to do is remove the string, you can do it like this:
let date = "2015-02-22T20:58:16+0000"
let display = date.substringToIndex(date.characters.indexOf("+")!)
This will give you the result of 2015-02-22T20:58:16

Swift get difference between two dates in GMT

I recently noticed strange behaviour trying to find the difference between two dates (in seconds).
I have a datestring that is in GMT time:
2016-01-07 01:09:47.289000
I want to find how many seconds since that time NOW.
But I notice that when I use NSDate() I get the time of my local time, not GMT time.
How would I go about doing this?
Use the NStimeZone class to set time zone
let date = NSDate()
var formatter = NSDateFormatter()
let gmt = NSTimeZone(abbreviation: "GMT")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
formatter.timeZone = gmt
formatter.stringFromDate(date)
To compare, convert the current date from NSDate to "GMT" and then calculate the time interval between the two.

NSDate set timezone in swift

how can i return a NSDate in a predefined time zone from a string
let responseString = "2015-8-17 GMT+05:30"
var dFormatter = NSDateFormatter()
dFormatter.dateFormat = "yyyy-M-dd ZZZZ"
var serverTime = dFormatter.dateFromString(responseString)
println("NSDate : \(serverTime!)")
the above code returns the time as
2015-08-16 18:30:00 +0000
The date format has to be assigned to the dateFormat property of the date formatter instead.
let date = NSDate.date()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.stringFromDate(date)
println(str)
This prints the date using the default time zone on the device. Only if you want the output according to a different time zone then you would add for example
Swift 3.*
dateFormatter.timeZone = NSTimeZone(name: "UTC")
Swift 4.*
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
also refer link http://www.brianjcoleman.com/tutorial-nsdate-in-swift/
how can i return a NSDate in a predefined time zone?
You can't.
An instance of NSDate does not carry any information about timezone or calendar. It just simply identifies one point in universal time.
You can interpret this NSDate object in whatever calendar you want. Swift's string interpolation (the last line of your example code) uses an NSDateFormatter that uses UTC (that's the "+0000" in the output).
If you want the NSDate's value as a string in the current user's calendar you have to explicitly set up a date formatter for that.
Swift 4.0
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
If you always have the same time zone for the input string, you can create two date formatters to output the local time zone (or a specified one):
let timeFormatterGet = DateFormatter()
timeFormatterGet.dateFormat = "h:mm a"
timeFormatterGet.timeZone = TimeZone(abbreviation: "PST")
let timeFormatterPrint = DateFormatter()
timeFormatterPrint.dateFormat = "h:mm a"
// timeFormatterPrint.timeZone = TimeZone(abbreviation: "EST") // if you want to specify timezone for output, otherwise leave this line blank and it will default to devices timezone
if let date = timeFormatterGet.date(from: "3:30 PM") {
print(timeFormatterPrint.string(from: date)). // "6:30 PM" if device in EST
} else {
print("There was an error decoding the string")
}
The number 1 means 1 regardless of language. Yet in English it's spelled as one, in Spanish it's una, in Arabic it wahid, etc.
Similarly 123982373 seconds pass 1970 is going to reflect differently in different timezones or calendar formats, but's all still 123982373 seconds passed 1970
The difference between 3 seconds and 7 seconds is 4 seconds. That doesn't require a calendar. Neither you need a calendar/timezone to know the difference in time between these two Epoch times 1585420200 and 1584729000
Dates are just a timeInterval from January 1, 1970 (midnight UTC/GMT). Dates also happen to have a string representation.
Repeating Nikolia's answer, Swift's default string interpolation (2015-08-16 18:30:00 +0000) uses a DateFormatter that uses UTC (that's the "+0000" in the output).
Calendars with the use of timezones give us a contextual representation that is just easier to understand than trying to calculate the difference between two gigantic numbers.
Meaning a single date (think of a single timeInterval since 1970) will have a different string interpretations per calendar. On top of that a calendar will itself vary based on time zones
I highly recommend that you go and play around with this Epoch converter site and see how selecting a different timezone will cause the string representations for the same moment/date/timeInterval to change
I also recommend to see this answer. Mainly this part:
Timezone is just an amendment to the timestamp string, it's not considered by the date formatter.
To consider the time zone you have to set the timeZone of the formatter
dateFormatter.timeZone = TimeZone(secondsFromGMT: -14400)