UTC t to local time junk data in swift [duplicate] - ios
I am getting the following string from a server in my iOS app:
20140621-061250
How can I convert it to the local time?
How can I define my date formatter? Is this correct?
dateFormatter.dateFormat = #"YYYYMMd-HHmmss";
The question doesn't specify the nature of what you mean by converting, exactly, but the first thing you should do, regardless of the final goal, is to correctly parse the server response using a properly configured NSDateFormatter. This requires specification of the correct format string, and the time zone must be explicitly set on the formatter or it will infer it from the local time, which would be incorrect in most cases.
Specify The Format String
Let's look at the input string provided:
20140621-061250
This uses four digits for the year, two digits (with a zero-padding) for the month, and two digits (presumably, these will be zero-padded as well) for the day. This is followed by a -, then two digits to represent the hour, 2 digits for the minute, and 2 digits for the second.
Referring to the Unicode date format standards, we can derive the format string in the following way. The four digits representing the calendar year will be replaced with yyyy in the format string. Use MM for the month, and dd for the day. Next would come the literal -. For the hours, I assume that it will be in 24 hour format as otherwise this response is ambiguous, so we use HH. Minutes are then mm and seconds ss. Concatenating the format specifiers yields the following format string, which we will use in the next step:
yyyyMMdd-HHmmss
In our program, this would look like:
NSString *dateFormat = #"yyyyMMdd-HHmmss";
Configure the input date formatter
The time format above does not specify a time zone, but because you have been provided the specification for the server response that it represents the UTC time, we can code this into our application. So, we instantiate an NSDateFormatter, set the correct time zone, and set the date format:
NSTimeZone *inputTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"UTC"];
NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
[inputDateFormatter setTimeZone:inputTimeZone];
[inputDateFormatter setDateFormat:dateFormat];
Convert the input string to an NSDate
For demonstration purposes, we hard-code the string you received from the server response; you would replace this definition of inputString with the one you get from the server:
NSString *inputString = #"20140621-061250";
NSDate *date = [inputDateFormatter dateFromString:inputString];
At this point, we have the necessary object to do any further conversions or calculations - an NSDate which represents the time communicated by the server. Remember, an NSDate is just a time stamp - it has no relation to a time zone whatsoever, which only plays a role when converting to and from string representations of the date, or representations of a calendrical date via NSDateComponents.
Next steps
The question doesn't clearly specify what type of conversion is needed, so we'll see an example of formatting the date to display in the same format as the server response (although, I can't think of a likely use case for this particular bit of code, to be honest). The steps are quite similar - we specify a format string, a time zone, configure a date formatter, and then generate a string (in the specified format) from the date:
NSTimeZone *outputTimeZone = [NSTimeZone localTimeZone];
NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init];
[outputDateFormatter setTimeZone:outputTimeZone];
[outputDateFormatter setDateFormat:dateFormat];
NSString *outputString = [outputDateFormatter stringFromDate:date];
Since I'm in UTC-06:00, printing outputString gives the following:
20140621-001250
It's likely you'll instead want to use setDateStyle: and setTimeStyle: instead of a format string if you're displaying this date to the user, or use an NSCalendar to get an NSDateComponents instance to do arithmetic or calculations on the date. An example for displaying a verbose date string to the user:
NSTimeZone *outputTimeZone = [NSTimeZone localTimeZone];
NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init];
[outputDateFormatter setTimeZone:outputTimeZone];
[outputDateFormatter setDateStyle:NSDateFormatterFullStyle];
[outputDateFormatter setTimeStyle:NSDateFormatterFullStyle];
NSString *outputString = [outputDateFormatter stringFromDate:date];
Printing outputString here gives us the following:
Saturday, June 21, 2014 at 12:12:50 AM Mountain Daylight Time
Note that setting the time zone appropriately will handle transitions over daylight savings time. Changing the input string to "20141121-061250" with the formatter style code above gives us the following date to display (Note that Mountain Standard Time is UTC-7):
Thursday, November 20, 2014 at 11:12:50 PM Mountain Standard Time
Summary
Any time you get date input in a string form representing a calendar date and time, your first step is to convert it using an NSDateFormatter configured for the input's format, time zone, and possibly locale and calendar, depending on the source of the input and your requirements. This will yield an NSDate which is an unambiguous representation of a moment in time. Following the creation of that NSDate, one can format it, style it, or convert it to date components as needed for your application requirements.
To get your string into a NSDate, you would use a NSDateFormatter like this:
NSString *myDateAsAStringValue = #"20140621-061250"
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyyMMdd-HHmmss"];
NSDate *myDate = [df dateFromString: myDateAsAStringValue];
You may want to read this post about working with Date and Time
EDIT:
To parse it as UTC you have to add the line:
[df setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
Also, when you print it with NSLog, if you are using the same NSDateFormatter, you will get the input string as output (since you apply the inverse of the parsing function).
Here is the full code, for parsing and for getting the output with a standard format:
//The input
NSString *myDateAsAStringValue = #"20140621-061250";
//create the formatter for parsing
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
[df setDateFormat:#"yyyyMMdd-HHmmss"];
//parsing the string and converting it to NSDate
NSDate *myDate = [df dateFromString: myDateAsAStringValue];
//create the formatter for the output
NSDateFormatter *out_df = [[NSDateFormatter alloc] init];
[out_df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssz"];
//output the date
NSLog(#"the date is %#",[out_df stringFromDate:myDate]);
One possible solution in Swift using NSDate extension (maybe it could help future viewers of this question):
import UIKit
// For your personal information: NSDate() initializer
// always returns a date in UTC, no matter the time zone specified.
extension NSDate {
// Convert UTC (or GMT) to local time
func toLocalTime() -> NSDate {
let timezone: NSTimeZone = NSTimeZone.localTimeZone()
let seconds: NSTimeInterval = NSTimeInterval(timezone.secondsFromGMTForDate(self))
return NSDate(timeInterval: seconds, sinceDate: self)
}
// Convert local time to UTC (or GMT)
func toGlobalTime() -> NSDate {
let timezone: NSTimeZone = NSTimeZone.localTimeZone()
let seconds: NSTimeInterval = -NSTimeInterval(timezone.secondsFromGMTForDate(self))
return NSDate(timeInterval: seconds, sinceDate: self)
}
}
Related
iOS - Converting time and date to user time zone
I am sending some requests on a webserver that replies me time and date like this: "at 18:58 of 05/08/2012" I can figure out how to get the time and the date in 2 NSStrings(18:58, 05/08/2012). Note that the server's time zone is +00:00. What I want to accomplish is to present this time based on user's location. So for example if the reply from server is 23:30 at 05/08/2012 and the user's time zone is +2:00 I want to present him 1:30 at 06/08/2012. Any ideas?
You should do it the following way: 1) First, create an NSDateFormatter to get the NSDate sent from the server: NSDateFormatter *serverFormatter = [[NSDateFormatter alloc] init]; [serverFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]]; [serverFormatter setDateFormat:#"'at 'HH:mm' of 'dd/MM/yyyy"]; From Apple docs: note with the Unicode format string format, you should enclose literal text in the format string between apostrophes (''). 2) Convert the string (consider it is defined as theString) to a NSDate: NSDate *theDate = [serverFormatter dateFromString:theString]; 3) Create an NSDateFormatter to convert theDate to the user: NSDateFormatter *userFormatter = [[NSDateFormatter alloc] init]; [userFormatter setDateFormat:#"HH:mm dd/MM/yyyy"]; [userFormatter setTimeZone:[NSTimeZone localTimeZone]]; 3) Get the string from the userFormatter: NSString *dateConverted = [userFormatter stringFromDate:theDate];
instead of getting absolute time from server get timestamp from server and convert that in to date at the client side, for this you didn't have to change the timezone also.
Objective-C, How can I get the current date in UTC timezone?
I am trying: NSDate *currentDateInLocal = [NSDate date]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:SS.SSS'Z'"]; NSString *currentLocalDateAsStr = [dateFormatter stringFromDate:currentDateInLocal]; NSDateFormatter * dateFormatter2 = [[NSDateFormatter alloc] init]; NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"UTC"]; [dateFormatter2 setTimeZone:timeZone]; [dateFormatter2 setDateFormat:#"yyyy-MM-dd'T'HH:mm:SS.SSS'Z'"]; NSDate *currentDateInUTC = [dateFormatter2 dateFromString:currentLocalDateAsStr]; but It's still does not represent the current UTC time, how can I achieve this? Thanks
You're overcomplicating things. NSDates don't have time zones or calendars. [NSDate date] gets the current date, which is a measurement of a moment in history. If I run [NSDate date] in Europe at exactly the same time as you run it in America then we'll get exactly the same value. How you print a date depends on the calendar and the time zone. So a date printed in the Gregorian calendar looks different from the same one printed in the Julian calendar. And a date printed in the UTC Gregorian calendar looks different from the same one printed in the PST Gregorian calendar. But they're still the same date. So you want to jump straight to your dateFormatter2.
The accepted answer by Alex Wien is incorrect. By default, NSDateFormatter adjusts the NSDate’s date-time value from UTC to the user's local time zone. To prevent that adjustment, tell the NSDateFormatter to use the time zone for UTC. To verify results, google "current time utc". My source code below should do the job, meaning get the current date-time as a string in ISO 8601 format in the UTC (Zulu) time zone signified by a Z on the end. NSDate* datetime = [NSDate date]; NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]]; // Prevent adjustment to user's local time zone. [dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; NSString* dateTimeInIsoFormatForZuluTimeZone = [dateFormatter stringFromDate:datetime]; You could put this logic in a pair of convenience methods somewhere in your app. - (NSString*)now { // Purpose: Return a string of the current date-time in UTC (Zulu) time zone in ISO 8601 format. return [self toStringFromDateTime:[NSDate date]]; } …and… - (NSString*)toStringFromDateTime:(NSDate*)datetime { // Purpose: Return a string of the specified date-time in UTC (Zulu) time zone in ISO 8601 format. // Example: 2013-10-25T06:59:43.431Z NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]]; [dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; NSString* dateTimeInIsoFormatForZuluTimeZone = [dateFormatter stringFromDate:datetime]; return dateTimeInIsoFormatForZuluTimeZone; } Example of usage… NSString* now = [self now]; Or turn those minus signs into plus signs to use as class methods rather than instance methods… NSString* now = [SomeClassNameHere now]; Tip: For better readability by humans, change that T in the format to a SPACE. For better interoperability by software, keep the T. The ISO 8601 spec tolerates a space but recommends keeping the T. Tip: I've not tested, but… Some people say instantiating [NSDateFormatter][4] is expensive. If doing so often (such as in a loop) consider caching a single instance for re-use.
NSDate *currentDate = [[NSDate alloc] init]; Now it is in UTC, (at least after using the method below) To store this time as UTC (since refernce date 1970) use double secsUtc1970 = [[NSDate date]timeIntervalSince1970]; Set Date formatter to output local time: NSTimeZone *timeZone = [NSTimeZone defaultTimeZone]; // or Timezone with specific name like // [NSTimeZone timeZoneWithName:#"Europe/Riga"] (see link below) NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeZone:timeZone]; [dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; NSString *localDateString = [dateFormatter stringFromDate:currentDate]; Available NSTimeZone names A NSDate object always uses UTC as time reference, but the string representation of a date is not neccessarily based on UTC timezone. Please note that UTC is not (only) a timeZone, It is a system how time on earth is measured, how it is coordinated (The C in UTC stands for coordinated). The NSDate is related to a reference Date of midnight 1.1.1970 UTC, altough slightly wrongly described by Apple as 1.1.1970 GMT. In the original question the last word timeZone is not perfect.
PLEASE SET UP Calendar Identifier !!! I am not too late! Because I saw no one set up the Calendar Identifier. It is really important for worldwide users. Many users using a non-Gregorian calendar. They will get wrong year string. Especially, when you need store it into your own database. (We met this problem before) NSCalendarIdentifierGregorian NSCalendarIdentifierBuddhist NSCalendarIdentifierChinese NSCalendarIdentifierHebrew NSCalendarIdentifierIslamic NSCalendarIdentifierIslamicCivil NSCalendarIdentifierJapanese NSCalendarIdentifierRepublicOfChina NSCalendarIdentifierPersian NSCalendarIdentifierIndian NSCalendarIdentifierISO8601 Code: -(NSString *)getUTCFormateDate:(NSDate *)localDate { NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"UTC"]; NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]; [dateFormatter setCalendar:gregorianCalendar]; [dateFormatter setTimeZone:timeZone]; [dateFormatter setLocale:locale]; [dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [dateFormatter stringFromDate:localDate]; return dateString; }
Swift 3 let utcTimestamp = Date().timeIntervalSince1970 print("timeStamp = \(utcTimestamp)") May following extension would be easier. Swift 4: UTC/GMT ⟺ Local (Current/System) extension Date { // Convert local time to UTC (or GMT) func toGlobalTime() -> Date { let timezone = TimeZone.current let seconds = -TimeInterval(timezone.secondsFromGMT(for: self)) return Date(timeInterval: seconds, since: self) } // Convert UTC (or GMT) to local time func toLocalTime() -> Date { let timezone = TimeZone.current let seconds = TimeInterval(timezone.secondsFromGMT(for: self)) return Date(timeInterval: seconds, since: self) } } // Try it let utcDate = Date().toGlobalTime() let localDate = utcDate.toLocalTime() print("utcDate - (utcDate)") print("localDate - (localDate)")
[NSDate date] is UTC. Maybe you get fooled by looking in the locals? Then it gets converted to your timezone. If you see the value in the locals, you see it in local time, but if you print it in the console, you see it in UTC. When you see '+0000' after the time, you know it is in UTC
Still another way to do it is like so in a C++ class in your Objective C project. (So, make a .mm file and build a C++ class with public and private parts, and stick this in the public part (unless you need it private).) Then, reference it like NSString *sNowUTC = MyClass::getUTCTimestamp();. static NSString *getUTCTimestamp(){ time_t rawtime; struct tm * timeinfo; char buffer [80]; time (&rawtime); timeinfo = gmtime (&rawtime); // make format like "2016-06-16 02:37:00" for // June 16, 2016 # 02:37:00 UTC time strftime (buffer,80,"%F %T",timeinfo); std::string sTime(buffer); NSString *sUTC = #(sTime.c_str()); return sUTC; }
This is what i used. static func makeISO8601Date(isoDateString: String) -> Date { let formatter = DateFormatter() formatter.calendar = Calendar(identifier: .iso8601) formatter.locale = Locale(identifier: "en_US_POSIX") formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" return formatter.date(from: isoDateString) } makeISO8601Date(isoDateString: "2017-12-31T23:59:59+00:00")
How to convert long-integer time to NSString or NSDate to display time?
I got a serial number form Java Date which convert into long-integer such as "1352101337000". The problem I met is how to analyze this long-integer number back to NSDate or NSString so that I can clear to know what time the serial number is displaying. Do anybody have solution for this case?
Use this, NSTimeInterval timeInMiliseconds = [[NSDate date] timeIntervalSince1970]; To change it back, NSDate* date = [NSDate dateWithTimeIntervalSince1970:timeInMiliseconds]; As per apple documentation, NSTimeInterval: Used to specify a time interval, in seconds. typedef double NSTimeInterval; It is of type double. To convert a date to string, NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss zzz"]; //Optionally for time zone converstions [formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]]; NSString *stringFromDate = [formatter stringFromDate:myNSDateInstance]; [formatter release];
Swift This answer has been updated for Swift 3, and thus no longer uses NSDate. Do the following steps to convert a long integer to a date string. // convert to seconds let timeInMilliseconds = 1352101337001 let timeInSeconds = Double(timeInMilliseconds) / 1000 // get the Date let dateTime = Date(timeIntervalSince1970: timeInSeconds) // display the date and time let formatter = DateFormatter() formatter.timeStyle = .medium formatter.dateStyle = .long print(formatter.string(from: dateTime)) // November 5, 2012 at 3:42:17 PM Notes Since Java dates are stored as long integers in milliseconds since 1970 this works. However, make sure this assumption is true before just converting any old integer to a date using the method above. If you are converting a time interval in seconds then don't divide by 1000, of course. There are other ways to do the conversion and display the string. See this fuller explanation.
Deviation from expected output with NSString to NSDate conversion using NSDateFormatter
I am using the below method to convert a NSString to NSDate. Always when I construct the NSDate from String, the date is one day behind the current day I have provided as part of the input and hour is 18:30:00 +0000. Why this deviation from what I have provided. I was expecting to have the same date what I have provided and hour as 00:00:00 +0000 +(NSDate*)convertStringToNSDate:(NSString*)string withFormat:(NSString*)format{ // Convert string to date object NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; //[dateFormat setTimeZone:[NSTimeZone localTimeZone]]; [dateFormat setDateFormat:format]; NSDate *date = [dateFormat dateFromString:string]; [dateFormat release]; return date; }
This question comes up quite regularly but I could not find a suitable duplicate (searching on the phone does not help). NSDate represents a specific point in time. When you log the value of an NSDate it is displayed in GMT, which is 5.5 hours behind your timezone (India, I assume). So the value is correct. If you run that date back through your date formatter you will get the local time of midnight again, since the date formatter is using your local time zone.
NSDate formatting from NSString
I have data in NSString, I need to display it as Oct 3, 2011. I am having trouble in converting nsstring into NSDate and then again display it as NSString. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:#"MMM d, yyyy "]; NSDate *dateFromString = [dateFormatter dateFromString:myString]; myString is 2011-10-3 00:00:00
First set the date formatter time zone. If the string you're receiving is GMT/UTC, set the timezone to that. Next set the date format to match the incoming date pattern. Do dateFromString. Then set the date format to match the desired output format. Also set the output timezone, if different. Do stringFromDate, using as input the NSDate object from the previous operation.