Nsdate Set Timezone in Swift

NSDate set timezone 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.

Converting date between timezones swift

Couldn't you just use your data formatter again with a different time zone and convert it? Such as

dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
let gmtDate = dateFormatter.dateFromString(string: "your old date as string here")

change NSDate from one time zone to another

NSString *str = @"2012-12-17 04:36:25";
NSDateFormatter* gmtDf = [[[NSDateFormatter alloc] init] autorelease];
[gmtDf setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
[gmtDf setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate* gmtDate = [gmtDf dateFromString:str];
NSLog(@"%@",gmtDate);

NSDateFormatter* estDf = [[[NSDateFormatter alloc] init] autorelease];
[estDf setTimeZone:[NSTimeZone timeZoneWithName:@"EST"]];
[estDf setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *estDate = [estDf dateFromString:[gmtDf stringFromDate:gmtDate]]; // you can also use str
NSLog(@"%@",estDate);

Edit : Adding swift code

let str: String = "2012-12-17 04:36:25"
let gmtDf: NSDateFormatter = NSDateFormatter()
gmtDf.timeZone = NSTimeZone(name: "GMT")
gmtDf.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate: NSDate = gmtDf.dateFromString(str)!
print(gmtDate)
let estDf: NSDateFormatter = NSDateFormatter()
estDf.timeZone = NSTimeZone(name: "EST")
estDf.dateFormat = "yyyy-MM-dd HH:mm:ss"
let estDate: NSDate = estDf.dateFromString(gmtDf.stringFromDate(gmtDate))!
print(estDate)

Edit: Adding Swift 3 code

    let str: String = "2012-12-17 04:36:25"
let gmtDf = DateFormatter()
gmtDf.timeZone = TimeZone(identifier: "GMT")
gmtDf.dateFormat = "yyyy-MM-dd HH:mm:ss"
let gmtDate = gmtDf.date(from: str)!
print(gmtDate)

let estDf = DateFormatter()
estDf.timeZone = TimeZone(identifier: "EST")
estDf.dateFormat = "yyyy-MM-dd HH:mm:ss"
let estDate = estDf.date(from: gmtDf.string(from: gmtDate))!
print(estDate)

Cannot change the timezone for DateFormatter in Swift 3

As maddy pointed out in the comments, Xcode is showing you the date in its "raw form" of Universal Timezone - UTZ - (also called Greenwich Meantime).

To get the date presented in another timezone you need to use the DateFormatter again.

So:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateStr1 = "2017-02-22"
let date1: Date = dateFormatter.date(from: dateStr1)!

print("\(date1)")
print("\(dateFormatter.string(from: date1))")

Gives you:

Print screen of code in playground with output.

I'm running this code in Perth, Western Australia (i.e. UTZ+8) - therefore when I convert 22-Feb-2017 into a date it is stored as 21-Feb-2017 UTZ, but if I present it back with a DateFormatter from my locale I get midnight, 22-Feb-2017.

NSDate() or Date() shows the wrong time

NSDate (or Date in Swift ≥ V3) does not have a time zone. It records an instant in time all over the world.

Internally, date objects record the number of seconds since the "epoch date", or Midnight on January 1, 2001 in Greenwich Mean Time, a.k.a UTC.

We normally think of dates in our local time zone.

If you log a date using

print(NSDate()) 

The system displays the current date, but it expresses it in UTC/Greenwich Mean Time. So the only place the time will look correct is in that time zone.

You get the same issue in the debugger if you issue the debugger command

e NSDate()

This is a pain. I personally wish iOS/Mac OS would display dates using the user's current time zone, but they don't.

EDIT #2:

An improvement on my previous use of localized string that makes it a little easier to use is to create an extension to the Date class:

extension Date {
func localString(dateStyle: DateFormatter.Style = .medium, timeStyle: DateFormatter.Style = .medium) -> String {
return DateFormatter.localizedString(from: self, dateStyle: dateStyle, timeStyle: timeStyle)
}
}

That way you can just use an expression like Date().localString(), or if you want to only print the time, you can use Date().localString(dateStyle:.none)

EDIT:

I just discovered that NSDateFormatter (DateFormatter in Swift 3) has a class method localizedString. That does what my extension below does, but more simply and cleanly. Here is the declaration:

class func localizedString(from date: Date, dateStyle dstyle: DateFormatter.Style, timeStyle tstyle: DateFormatter.Style) -> String

So you'd simply use

let now = Date()
print (DateFormatter.localizedString(
from: now,
dateStyle: .short,
timeStyle: .short))

You can pretty much ignore everything below.


I have created a category of the NSDate class (Date in swift 3) that has a method localDateString that displays a date in the user's local time zone.

Here is the category in Swift 3 form: (filename Date_displayString.swift)

extension Date {
@nonobjc static var localFormatter: DateFormatter = {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateStyle = .medium
dateStringFormatter.timeStyle = .medium
return dateStringFormatter
}()

func localDateString() -> String
{
return Date.localFormatter.string(from: self)
}
}

And in Swift 2 form:

extension NSDate {
@nonobjc static var localFormatter: NSDateFormatter = {
let dateStringFormatter = NSDateFormatter()
dateStringFormatter.dateStyle = .MediumStyle
dateStringFormatter.timeStyle = .MediumStyle
return dateStringFormatter
}()

public func localDateString() -> String
{
return NSDate.localFormatter.stringFromDate(self)
}
}

(If you prefer a different date format it's pretty easy to modify the format used by the date formatters. It's also straightforward to display the date and time in any timezone you need.)

I would suggest putting the appropriate Swift 2/Swift 3 version of this file in all of your projects.

You can then use

Swift 2:

print(NSDate().localDateString())

Swift 3:

print(Date().localDateString())

Get NSDate from NSDate adjusted with timezone

NSDate only represents an absolute point in time. It has no concept of timezone or calendar. When you create a NSDate instance it is just a number of seconds since January 1st 2001 GMT! It does not matter if you are in New York, Tokyo, Barcelona or Jerusalem.

At your example, you instance the NSDate based on GMT, but [date description] (used in NSLog) translates it into your local time. There you have the mismatch.

So there are two parts to consider:

1. NSDate creation using NSCalendar and NSTimeZone

If you are creating a date manually you should specify the calendar (2012 in Gregorian, but 5772 in Hebrew) and time zone (22PM London time, but 7AM Sydney time).

// Use the user's current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone: [NSTimeZone systemTimeZone]];

// Specify the date components manually (year, month, day, hour, minutes, etc.)
NSDateComponents *timeZoneComps=[[NSDateComponents alloc] init];
[timeZoneComps setHour:22];
[timeZoneComps setMinute:0];
[timeZoneComps setSecond:0];
// ... year, month, ...

// transform the date compoments into a date, based on current calendar settings
NSDate *date = [calendar dateFromComponents:timeZoneComps];

At this point date stores the exact point in time (in seconds) representing the current calendar.

2. NSDate output using NSDateFormatter

For a controlled output of your NSDate you need NSDateFormatter, which is used to convert dates into strings.

Based on Apple NSDateFormatter Class Reference documentation

There are many attributes you can get and set on a style date
formatter
, ...
You are encouraged, however, not to change individual settings. Instead you should accept the default settings established on initialization and specify the format using setDateStyle:, setTimeStyle:

This is specially important for the output, which is different for every locale. By default NSDateFormatter observes the current user’s locale settings. So the same NSDate could be 22.11.2011 18:33:19, or Nov 22, 2011 6:33:19 PM, or 2011-11-22 下午6:33:19 or even २२-११-२०११ ६:३३:१९ अपराह्, all for the same input and with the same code.

And the code:

//  NSDate *date -> NSString *dateString 

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];

// Medium style date, short style time => "Nov 23, 1937 3:30pm"
NSString *dateString = [dateFormatter stringFromDate:date];

Or you could transform it using the class method localizedStringFromDate:dateStyle:timeStyle:

I hope this clarifies the problem.



Related Topics



Leave a reply



Submit