Swift: NSDate formatting with strftime & localtime - objective-c

How do I convert the following Objective-C code into Swift code?
#define MAX_SIZE 11
char buffer[MAX_SIZE];
time_t time = [[NSDate date] timeIntervalSince1970];
strftime(buffer, MAX_SIZE, "%-l:%M\u2008%p", localtime(&time));
NSString *dateString = [NSString stringWithUTF8String:buffer];
NSLog(#"dateString: %#", dateString); // dateString: 11:56 PM
I'm formatting a date.

As the commentators #BryanChen and #JasonCoco said, use NSDateFormatter.
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd 'at' h:mm a" // superset of OP's format
let str = dateFormatter.stringFromDate(NSDate())
A full description of the format strings is available in "Data Formatting Guide".

Here is another example that uses NSDateFormatterStyle:
private func FormatDate(date:NSDate) -> String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.LongStyle
return dateFormatter.stringFromDate(date)
}
The output is formatted as, "January 1, 1990".
If you want to read more about the formatter and the different available styles, checkout, NSFormatter under NSDateFormatter section.

My function i use.
extension NSDate {
public func toString (format: String) -> String {
let formatter = NSDateFormatter ()
formatter.locale = NSLocale.currentLocale()
formatter.dateFormat = format
return formatter.stringFromDate(self)
}
}
date.toString("yyyy-MM-dd")

let maxSize: UInt = 11
var buffer: CChar[] = CChar[](count: Int(maxSize), repeatedValue: 0)
var time: time_t = Int(NSDate().timeIntervalSince1970)
var length = strftime(&buffer, maxSize, "%-l:%M\u2008%p", localtime(&time))
var dateString = NSString(bytes: buffer, length: Int(length), encoding: NSUTF8StringEncoding)
NSLog("dateString: %#", dateString) // dateString: 11:56 PM

Related

Variable 'dateFormatter' used before being initialized in iOS Swift

I am using NSDateFormatter in my project using Swift language.
I am getting following error:
Variable 'dateFormatter' used before being initialized
My code:
var date : NSDate = (NSDate.date())
var dateFormatter : NSDateFormatter
dateFormatter.dateFormat = "dd:mm:yyyy HH:mm:ss zzz"
Change just one line.
You not initialise the NSDateFormatter
change below line:
var dateFormatter : NSDateFormatter = NSDateFormatter()
Complete code:
var date : NSDate = (NSDate.date())
var dateFormatter : NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd:mm:yyyy HH:mm:ss zzz"
New usage would be:
let date = Date()
let formatter = DateFormatter()
formatter.dateFormat = "MM.dd.yy" // or whatever format
let dateStr = formatter.string(from: date)
First you need to initialise, then you won't get error.
In Swift, initilization completes with ().
var dateFormatter = NSDateFormatter()

Unable to convert original date using dateFromString

I am trying to convert a time string using the following code
NSString *origDate = #"2012-12-06T09:27:18+08:00";
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setFormatterBehavior:NSDateFormatterBehavior10_4];
[df setDateFormat:#"yyyy-mm-dd HH:mm:ss VVVV"];
NSDate *convertedDate = [df dateFromString:origDate];
However when I print the convertedDate, it returns me null. My guess is that the Date format U am using does not match. How can I modify the code to make it work? What format can I use to match my string?
EDIT (After referring to apple's documentation)
I checked the date format documentation on apple's page and found the following code
NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[rfc3339DateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
[rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
// Convert the RFC 3339 date time string to an NSDate.
NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
The format above seems to match what I have in the original date string "2012-12-06T09:27:18+08:00". However I am still getting a null value back. Am I getting closer? How else can I update this?
Based on your original input, this format string provided to your date formatter should get the job done:
#"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"
Note: I had tested this under Mac OS X 10.8.2.
The format String will parse on iOS6 (not iOS5 -> nil) but it is useless for output, since the parsed date will loose it's timezone information.
Output will be something like "2012-12-06T17:27:18Z" in iOS6 maybe this is depending on wether the timezone is set to GMT.
my Code:
static NSDateFormatter *gXmlDateFormatter = nil;
// lazy init
+ (NSDateFormatter *)xmlDateFormatter
{
// e.g. updateDateTime="2012-09-18T11:06:19+00:00"
if (gXmlDateFormatter == nil) {
// prepare for parsinf Arinc-ISO-XML-dates input
gXmlDateFormatter = [[NSDateFormatter alloc] init];
gXmlDateFormatter = [NSTimeZone timeZoneForSecondsFromGMT:0];
gXmlDateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
gXmlDateFormatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"; // only parsing! in iOS 6 (iOS5 will parse nil)
// gXmlDateFormatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"; // all iOS but with NO colons in timeZone (add/remove)
}
NSLog(#"gXmlDateFormatter:%#",gXmlDateFormatter);
return gXmlDateFormatter;
}
// there's a problem with the above dateformater and iOS5 creating nil-results
+ (NSDate *)dateFromXMLString:(NSString *)arincDateString
{
NSString *dateString = arincDateString;
// xmlDateStrings may contain a ':' in the timezone part. iOS and Unicode DO NOT
// so always remove the xml-standard colon ':' from the timezone to make it iOS/Unicode compatible
// xml: http://www.w3schools.com/schema/schema_dtypes_date.asp
// iOS: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns)
NSRange zRange = NSMakeRange(arincDateString.length-3, 1);
dateString = [arincDateString stringByReplacingOccurrencesOfString:#":" withString:#"" options:0 range:zRange];
NSDate *date = [self.arincDateFormatter dateFromString:dateString];
if(!date)NSLog(#"PARSING arincDateString:'%#' -> (NSDate*)%# ",arincDateString,date);
return date;
}
+ (NSString *)xmlStringFromDate:(NSDate *)date
{
if( !date ) return nil; // exit on nil date
#autoreleasepool {
NSString *dateString = [self.arincDateFormatter stringFromDate:date];
// iOS5 does not use a ':' in the timeZone part but xml needs it
// so allways add the xml-standard colon ':' into the timezone
NSMutableString *string = [NSMutableString stringWithString:dateString];
if( 22 < string.length ) { // prevent crashing
[string insertString:#":" atIndex:22];
} else {
NSLog(#"date output string too short:%d<22",string.length);
}
dateString = string;
if(!dateString)
NSLog(#"OUTPUT '%#' -> (NSString*)%#",date,dateString);
return dateString;
}
}

NSTimeInterval Formatting

I want to take my NSTimeInterval and format it into a string as 00:00:00 (hours, minutes, seconds). What is the best way to do this?
Since iOS 8.0 there is now NSDateComponentsFormatter which has a stringFromTimeInterval: method.
[[NSDateComponentsFormatter new] stringFromTimeInterval:timeInterval];
"Best" is subjective. The simplest way is this:
unsigned int seconds = (unsigned int)round(myTimeInterval);
NSString *string = [NSString stringWithFormat:#"%02u:%02u:%02u",
seconds / 3600, (seconds / 60) % 60, seconds % 60];
UPDATE
As of iOS 8.0 and Mac OS X 10.10 (Yosemite), you can use NSDateComponentsFormatter if you need a locale-compliant solution. Example:
NSTimeInterval interval = 1234.56;
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute |
NSCalendarUnitSecond;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
NSString *string = [formatter stringFromTimeInterval:interval];
NSLog(#"%#", string);
// output: 0:20:34
However, I don't see a way to force it to output two digits for the hour, so if that's important to you, you'll need to use a different solution.
NSTimeInterval interval = ...;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
NSString *formattedDate = [dateFormatter stringFromDate:date];
NSLog(#"hh:mm:ss %#", formattedDate);
swift 4.2
extension Date {
static func timestampString(timeInterval: TimeInterval) -> String? {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad
formatter.maximumUnitCount = 0
formatter.allowedUnits = [.hour, .minute, .second]
return formatter.string(from: timeInterval)
}
}
Test code:
let hour = 60 * 50 * 32
Date.timestampString(timeInterval: TimeInterval(hour))
// output "26:40:00"
Change unitStyle to get different styles. like formatter.unitsStyle = .abbreviated get
output: "26h 40m 0s"
A Swift version of #Michael Frederick's answer :
let duration: NSTimeInterval = ...
let durationDate = NSDate(timeIntervalSince1970: duration)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let durationString = dateFormatter.stringFromDate(durationDate)

Detect if time format is in 12hr or 24hr format

Is there any way to detect if the current device of the app uses 12h our 24h format, so that I can use one NSDateFormatter for 12h and one for 24h depending on the users language/loaction setting? Just Like the UIDatePicker detects and shows the AM/PM picker if it is 12h format.
I figured it out, its pretty easy. I just added this code to viewDidLoad :
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setDateStyle:NSDateFormatterNoStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSString *dateString = [formatter stringFromDate:[NSDate date]];
NSRange amRange = [dateString rangeOfString:[formatter AMSymbol]];
NSRange pmRange = [dateString rangeOfString:[formatter PMSymbol]];
BOOL is24h = (amRange.location == NSNotFound && pmRange.location == NSNotFound);
[formatter release];
NSLog(#"%#\n",(is24h ? #"YES" : #"NO"));
And it perfectly returns YES or NO depending on the locale.
And here is a Swift 3.0 updated version
func using12hClockFormat() -> Bool {
let formatter = DateFormatter()
formatter.locale = Locale.current
formatter.dateStyle = .none
formatter.timeStyle = .short
let dateString = formatter.string(from: Date())
let amRange = dateString.range(of: formatter.amSymbol)
let pmRange = dateString.range(of: formatter.pmSymbol)
return !(pmRange == nil && amRange == nil)
}
this is swift solution that worked for me, those two above did not.
let dateString: String = DateFormatter.dateFormat(
fromTemplate: "j", options: 0,
locale: Locale.current
)!
if(dateString.contains("a")){
// 12 h format
return true
}else{
// 24 h format
return false
}
For Swift 5.3.
Tested on Xcode 12.
func is12hClockFormat() -> Bool {
let formatString = DateFormatter.dateFormat(
fromTemplate: "j",
options: 0,
locale: Locale.current
)!
return formatString.contains("a")
}
This uses a special date template string called "j". According to the ICU Spec, "j"...
requests the preferred hour format for the locale (h, H, K, or k), as determined by whether h, H, K, or k is used in the standard short time format for the locale. In the implementation of such an API, 'j' must be replaced by h, H, K, or k before beginning a match against availableFormats data. Note that use of 'j' in a skeleton passed to an API is the only way to have a skeleton request a locale's preferred time cycle type (12-hour or 24-hour).
That last sentence is important. It "is the only way to have a skeleton request a locale's preferred time cycle type". Since NSDateFormatter and NSCalendar are built on the ICU library, the same holds true here.
Collected from https://stackoverflow.com/a/11660380/3428146
Here is the Swift version:
func using12hClockFormat() -> Bool {
let formatter = NSDateFormatter()
formatter.locale = NSLocale.currentLocale()
formatter.dateStyle = NSDateFormatterStyle.NoStyle
formatter.timeStyle = NSDateFormatterStyle.ShortStyle
let dateString = formatter.stringFromDate(NSDate())
let amRange = dateString.rangeOfString(formatter.AMSymbol)
let pmRange = dateString.rangeOfString(formatter.PMSymbol)
return !(pmRange == nil && amRange == nil)
}
Objective C category NSDate+Extensions:
#import Foundation;
#interface NSDate (Extensions)
- (NSString *)getTimeString;
#end
#import "NSDate+Extensions.h"
#implementation NSDate (Extensions)
- (NSString *)getTimeString
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
if ([self isTwelveHourDateFormat]) {
[formatter setDateFormat:#"hh:mm\ndd MMM"];
}
else {
[formatter setDateFormat:#"HH:mm\ndd MMM"];
}
return [formatter stringFromDate:self];
}
- (BOOL)isTwelveHourDateFormat
{
NSString *dateFormat = [NSDateFormatter dateFormatFromTemplate:#"j" options:0 locale:[NSLocale currentLocale]];
return [dateFormat containsString:#"a"];
}
#end

Convert NSDate to NSString

How do I convert, NSDate to NSString so that only the year in #"yyyy" format is output to the string?
How about...
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy"];
//Optionally for time zone conversions
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]];
NSString *stringFromDate = [formatter stringFromDate:myNSDateInstance];
//unless ARC is active
[formatter release];
Swift 4.2 :
func stringFromDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "dd MMM yyyy HH:mm" //yyyy
return formatter.string(from: date)
}
I don't know how we all missed this: localizedStringFromDate:dateStyle:timeStyle:
NSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date]
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterFullStyle];
NSLog(#"%#",dateString);
outputs '13/06/12 00:22:39 GMT+03:00'
Hope to add more value by providing the normal formatter including the year, month and day with the time.
You can use this formatter for more than just a year
[dateFormat setDateFormat: #"yyyy-MM-dd HH:mm:ss zzz"];
there are a number of NSDate helpers on the web, I tend to use:
https://github.com/billymeltdown/nsdate-helper/
Readme extract below:
NSString *displayString = [NSDate stringForDisplayFromDate:date];
This produces the following kinds of output:
‘3:42 AM’ – if the date is after midnight today
‘Tuesday’ – if the date is within the last seven days
‘Mar 1’ – if the date is within the current calendar year
‘Mar 1, 2008’ – else ;-)
In Swift:
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy"
var dateString = formatter.stringFromDate(YourNSDateInstanceHERE)
NSDateFormatter *dateformate=[[NSDateFormatter alloc]init];
[dateformate setDateFormat:#"yyyy"]; // Date formater
NSString *date = [dateformate stringFromDate:[NSDate date]]; // Convert date to string
NSLog(#"date :%#",date);
If you don't have NSDate -descriptionWithCalendarFormat:timeZone:locale: available (I don't believe iPhone/Cocoa Touch includes this) you may need to use strftime and monkey around with some C-style strings. You can get the UNIX timestamp from an NSDate using NSDate -timeIntervalSince1970.
+(NSString*)date2str:(NSDate*)myNSDateInstance onlyDate:(BOOL)onlyDate{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
if (onlyDate) {
[formatter setDateFormat:#"yyyy-MM-dd"];
}else{
[formatter setDateFormat: #"yyyy-MM-dd HH:mm:ss"];
}
//Optionally for time zone conversions
// [formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]];
NSString *stringFromDate = [formatter stringFromDate:myNSDateInstance];
return stringFromDate;
}
+(NSDate*)str2date:(NSString*)dateStr{
if ([dateStr isKindOfClass:[NSDate class]]) {
return (NSDate*)dateStr;
}
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [dateFormat dateFromString:dateStr];
return date;
}
Just add this extension:
extension NSDate {
var stringValue: String {
let formatter = NSDateFormatter()
formatter.dateFormat = "yourDateFormat"
return formatter.stringFromDate(self)
}
}
If you are on Mac OS X you can write:
NSString* s = [[NSDate date] descriptionWithCalendarFormat:#"%Y_%m_%d_%H_%M_%S" timeZone:nil locale:nil];
However this is not available on iOS.
It's swift format :
func dateFormatterWithCalendar(calndarIdentifier: Calendar.Identifier, dateFormat: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: calndarIdentifier)
formatter.dateFormat = dateFormat
return formatter
}
//Usage
let date = Date()
let fotmatter = dateFormatterWithCalendar(calndarIdentifier: .gregorian, dateFormat: "yyyy")
let dateString = fotmatter.string(from: date)
print(dateString) //2018
swift 4 answer
static let dateformat: String = "yyyy-MM-dd'T'HH:mm:ss"
public static func stringTodate(strDate : String) -> Date
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateformat
let date = dateFormatter.date(from: strDate)
return date!
}
public static func dateToString(inputdate : Date) -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateformat
return formatter.string(from: inputdate)
}
Use extension to have clear code
You can write an extension to convert any Date object to any desired calendar and any format
extension Date{
func asString(format: String = "yy/MM/dd HH:mm",
for identifier: Calendar.Identifier = .persian) -> String {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: identifier)
formatter.dateFormat = format
return formatter.string(from: self)
}
}
Then use it like this:
let now = Date()
print(now.asString()) // prints -> 00/04/18 20:25
print(now.asString(format: "yyyy/MM/dd")) // prints -> 1400/04/18
print(now.asString(format: "MM/dd", for: .gregorian)) // prints -> 07/09
To learn how to specify your desired format string take a look at this link.
For a complete reference on how to format dates see Apple's official Date Formatting Guide here.
Simple way to use C# styled way to convert Date to String.
usage:
let a = time.asString()
// 1990-03-25
let b = time.asString("MM ∕ dd ∕ yyyy, hh꞉mm a")
// 03 / 25 / 1990, 10:33 PM
extensions:
extension Date {
func asString(_ template: String? = nil) -> String {
if let template = template {
let df = DateFormatter.with(template: template)
return df.string(from: self)
}
else {
return globalDateFormatter.string(from: self)
}
}
}
// Here you can set default template for DateFormatter
public let globalDateFormatter: DateFormatter = DateFormatter.with(template: "y-M-d")
public extension DateFormatter {
static func with(template: String ) -> DateFormatter {
let df = DateFormatter()
df.dateFormat = template
return df
}
}
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:myNSDateInstance];
NSInteger year = [components year];
// NSInteger month = [components month];
NSString *yearStr = [NSString stringWithFormat:#"%ld", year];
Define your own utility for format your date required date format
for eg.
NSString * stringFromDate(NSDate *date)
{ NSDateFormatter *formatter
[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM ∕ dd ∕ yyyy, hh꞉mm a"];
return [formatter stringFromDate:date];
}
#ios #swift #convertDateinString
Simply just do like this to "convert date into string" as per format you passed:
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-YYYY" // pass formate here
let myString = formatter.string(from: date) // this will convert Date in String
Note: You can specify different formats such like "yyyy-MM-dd", "yyyy", "MM" etc...
Update for iOS 15
iOS 15 now supports calling .formatted on Date objects directly without an explicit DateFormatter.
Example for common formats
Documentation
date.formatted() // 6/8/2021, 7:30 PM
date.formatted(date: .omitted, time: .complete) // 19:30
date.formatted(date: .omitted, time: .standard) // 07:30 PM
date.formatted(date: .omitted, time: .shortened) // 7:30 PM
date.formatted(date: .omitted, time: .omitted)
Alternative syntax
Documentation
// We can also specify each DateComponent separately by chaining modifiers.
date.formatted(.dateTime.weekday(.wide).day().month().hour().minute())
// Tuesday, Jun 8, 7:30 pm
// Answer to specific question
date.formatted(.dateTime.year())
for Objective-C:
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy";
NSString *dateString = [formatter stringFromDate:date];
for Swift:
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy"
let dateString = formatter.string(from: now)
That's a good website for nsdateformatter.You can preview date strings with different DateFormatter in different local.