iOS Nsdate() Returns Incorrect Time

iOS NSDate() returns incorrect time

It doesn't return the wrong time. It returns exactly the right time. NSDate doesn't have any timezone information. Right now, my computer and your computer will report the exact same time when we call NSDate ().

NSLog displays NSDate in UTC. That's just what it displays. So if we both call NSLog right now, your computer will log the same date and time as mine. Because it is the same date and time.

If you want to process an NSDate (for example, to display the date and time to a user) you use an NSCalendar. The NSCalendar translates between NSDate, which is the same everywhere in the world, to the values that you want to display in your user interface, which will be different in London or in Kiev. If I look on my watch right now, I will see a different time than you see on your watch, and that is what NSCalendar is there for.

iOS NSDate() returns incorrect time

It doesn't return the wrong time. It returns exactly the right time. NSDate doesn't have any timezone information. Right now, my computer and your computer will report the exact same time when we call NSDate ().

NSLog displays NSDate in UTC. That's just what it displays. So if we both call NSLog right now, your computer will log the same date and time as mine. Because it is the same date and time.

If you want to process an NSDate (for example, to display the date and time to a user) you use an NSCalendar. The NSCalendar translates between NSDate, which is the same everywhere in the world, to the values that you want to display in your user interface, which will be different in London or in Kiev. If I look on my watch right now, I will see a different time than you see on your watch, and that is what NSCalendar is there for.

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())

NSDate date method returns wrong result

NSDates are always stored in UTC, actually the dates itselfs dont know anything about timezones or weeks, month, years. They are just a point in time.

To see the correct time for your position on the earth surface, you need to take the NSCalendar, that represents your time model in account. You could use it directly and mess around with your dates, or create a NSDateFormatter that will leave the dates untouched but adjust their appearence to your needs.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterFullStyle];

NSLog(@"%@", [formatter stringFromDate: date1]);

results in

Thursday, July 12, 2012, 4:36:07 PM Central European Summer Time 

in response to the comment:

try this code as test

NSDate *now = [NSDate date];
NSDate *startOfToday = nil;
NSDate *startOfThisWeek = nil;
NSDate *startOfThisMonth = nil;
NSDate *startOfThisYear = nil;
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit startDate:&startOfThisWeek interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSMonthCalendarUnit startDate:&startOfThisMonth interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSYearCalendarUnit startDate:&startOfThisYear interval:NULL forDate:now];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterFullStyle];

NSLog(@"%@", now);
NSLog(@"%@", [formatter stringFromDate:now]);

NSLog(@"%@", startOfToday);
NSLog(@"%@", [formatter stringFromDate:startOfToday]);

NSLog(@"%@", startOfThisWeek);
NSLog(@"%@", [formatter stringFromDate:startOfThisWeek]);

NSLog(@"%@", startOfThisMonth);
NSLog(@"%@", [formatter stringFromDate:startOfThisMonth]);

NSLog(@"%@", startOfThisYear);
NSLog(@"%@", [formatter stringFromDate:startOfThisYear]);

you will realize, that the start of the day, week, month and year will be adjusted to your local time, as the first of each NSLog-pair will give you the date in UTC and the second in your local time zone.


on the chat you posted this code

NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; 
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm"];
[dateFormat setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDate *date = [dateFormat dateFromString:dateString];
[dateFormat release];

so the problem is, that the datestring is actually not from GMT, but EET (Eastern European Time)

try

[dateFormat setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"EET"]]; 

but the by far most elegant solution would be to get the datestring with the offset to UTC, similar to 2012-07-12 12:23:00 +0300if some how possible.

In such an case you could parse it with

[dateFormat setDateFormat:@"yyyy-mm-dd HH:mm:ss Z"];
and don't need further time zone handling, as the formatter knows the offset via the Z-specifier.

Also note, that if you don't set any timezone, the device's current should be used. If the user is always in the same timezone as the time from the date string, this should work, too. But if the user leaves that zone, or you inted to have it working world wide, you should use one of the solutions I gave you. With the second (specifying the timezone with-in the datestring) as the preferred one.

Date() shows wrong time

From Apple's documentation:

A Date is independent of a particular calendar or time zone. To
represent a Date to a user, you must interpret it in the context of a
Calendar.

You need the help of Calendar:

let calendar = Calendar(identifier: .gregorian)
let currentDate = Date()
print(calendar.dateComponents(in: calendar.timeZone, from: currentDate))

the output will be:

calendar: gregorian (fixed) timeZone: Europe/Bratislava (current) era: 1 year: 2019 
month: 11 day: 19 hour: 15 minute: 47 second: 14 nanosecond: 285109996 weekday: 3 weekdayOrdinal: 3 quarter: 0 weekOfMonth: 4 weekOfYear: 47 yearForWeekOfYear: 2019 isLeapMonth: false

So you could then access your calendar's components like hour, minute etc.

UPDATE:

@Camile answered in comments to their question using DateFormatter:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss:Z"
dateFormatter.timeZone = calendar.timeZone
dateFormatter.string(from:currentDate)

will give you

2019-11-19 16:38:03:+0100

NSDate returning wrong date in Swift


  1. You are using the wrong specifier for the day of the month.
  2. You are creating your date string the hardest way possible.

Try this:

Swift 3/4:

func dF(_ someDate: Date) -> String {
let format = DateFormatter()
format.dateFormat = "MMM d"
// For a more localized format, use the following instead:
// format.setLocalizedDateFormatFromTemplate("MMMd")

let conString = format.string(from: someDate)

return conString
}

Old Swift 2 answer:
func dF(someDate:NSDate) -> (String){
let format = NSDateFormatter()
format.dateFormat = "MMM d"

    let conString = format.stringFromDate(someDate)

return (conString)
}

NSCalendar.dateFromComponents returns wrong time

You can solve your problem by setting the timezone correctly.
For example :

calendar?.timeZone = NSTimeZone(abbreviation: "GMT")!

NSDateFormatter dateFromString returns incorrect date

I don't believe that Dhruv's answer is correct. In fact, it's not clear there's any problem at all. You just seem to have an incorrect expectation of what should happen and/or interpretation of what's happening.

NSDate represents a moment in time. This moment does not have one unique name. It will be known by different names in different places and under different naming systems (time zones, calendars). NSDate doesn't deal with any of this, except lamely in its -description method, where it has to produce a string representation of that moment.

Second, a string like "02-06-2012" doesn't specify a precise moment in time. First of all, it's just a date with no time information, so NSDateFormatter just defaults to the first moment for that date. Second, it doesn't specify the time zone. The first moment of the calendar day is a different moment in each time zone. Unless you specify a time zone with -setTimeZone: or the string itself carries time zone information, NSDateFormatter assumes that any date strings you ask it to parse are in the current time zone.

So, your dateFromString object represents the first moment of the specified date, 02-06-2012, in your time zone. I expect this is what you wanted. However, you then got confused by the way that NSDate describes itself when logged. As I said, NSDate has to pick some "name" (string representation) for the moment it represents and which name it picks is fairly arbitrary. These days it is picking the name that the moment is known by in UTC. I gather from the log output shown in your question that you are located at UTC+0100. So, the date may look like it's one day earlier but it really is the same moment you specified. In other words, "2012-06-01 23:00:00 +0000" and "2012-06-02 00:00:00 +0100" are two equivalent names for exactly the same moment in time. You just aren't used to seeing the first one and misinterpreted it.

The lesson is that you have to stop relying on NSDate's self-description to be in any particular time zone. Really, you have to not rely on anything about it, since it's not documented. In fact, the docs for -[NSDate description] state, "The representation is not guaranteed to remain constant across different releases of the operating system."

Dhruv's solution seems to help merely because it causes NSDateFormatter and -[NSDate description] to agree on the time zone. But that's unreliable. It wouldn't work on Snow Leopard, for example, because -[NSDate description] used the local time zone instead of UTC in that version of the frameworks.

More importantly, though, it alters the actual moment represented by the NSDate object you get from NSDateFormatter's interpretation of your date string. I suspect you really want that to have a specific meaning – you want the string to be interpreted as being in the local time zone – and his solution thwarts your intent.

tl;dr: you were getting the date you wanted all along; don't rely on -[NSDate description]; don't use Dhruv's solution



Related Topics



Leave a reply



Submit