Reputation: 5093
Important:
To start with, I did:
NSInteger tzOffset = [[NSTimeZone systemTimeZone] secondsFromGMT];
NSDate *localDate = [inputDate dateByAddingTimeInterval:tzOffset];
int daylightOffset = [[NSTimeZone localTimeZone] daylightSavingTimeOffset];
BOOL isDaylightSavingTimeForDate =
[[NSTimeZone localTimeZone] isDaylightSavingTimeForDate:inputDate];
if (!isDaylightSavingTimeForDate) {
localDate = [localDate dateByAddingTimeInterval:-1*daylightOffset];
}
time_t localTime = (time_t) [localDate timeIntervalSince1970];
It works only if DaylightOffset
is active for system. It does not work when
[[NSTimeZone localTimeZone] daylightSavingTimeOffset]
returns 0
;isDaylightSavingTimeForDate:inputDate
returns true
Is there better way to convert NSDate to time_t with value representing local TZ
Example:
I live in PST. In Nov 2017 UTC = -8 hours, In May 2018, UTC = -7 hours
what I want is localDate = 2018-05-04 13:00:00 UTC
Upvotes: 0
Views: 770
Reputation: 5093
This is how I solved my problem.
int daylightOffsetSystem = [[NSTimeZone localTimeZone] daylightSavingTimeOffset];
int daylightOffsetForStartDate = [[NSTimeZone localTimeZone] daylightSavingTimeOffsetForDate:startDate];
BOOL isDaylightSavingTimeForStartDate = [[NSTimeZone localTimeZone] isDaylightSavingTimeForDate:startDate];
if (isDaylightSavingTimeForStartDate) {
if (daylightOffsetSystem == 0) {
localStartDate = [localStartDate dateByAddingTimeInterval:daylightOffsetForStartDate];
}
} else {
localStartDate = [localStartDate dateByAddingTimeInterval:-1*daylightOffsetSystem];
}
NSInteger tzOffset = [[NSTimeZone systemTimeZone] secondsFromGMT];
localStartDate = [localStartDate dateByAddingTimeInterval:tzOffset];
Upvotes: -1
Reputation: 299555
I need to convert NSDate to time_t
time_t time = (time_t)[date timeIntervalSince1970];
That is the entire answer.
NSDate contains time in UTC
NSDate never contains a time zone of any kind. NSDate is an absolute number of seconds since a reference time. It does not matter what time zone you are in. It does not matter if you're on Earth. It does not matter what calendar, clock, or other human device you are using. It is an absolute point in time that everyone will agree on (ignoring relativistic effects).
time_t must contain value in local timezone
time_t is the same as NSDate. It has no time zone, ever. It is a number of seconds since an epoch. If you think it has a time zone, or want it to have a time zone, you are using the wrong tool.
In Nov 2017, I want to to display May 04, 2018 1:00PM.
(emphasis mine) If you want to display something, you want an NSDateFormatter
. You do not want to change the number of seconds a particular event is from the epoch, you just want to describe it in a time-zone aware way.
If you want to do computations on a calendar-based date, then you want NSDateComponents
. It an handle adding things like "hours" and "days." The only unit of time that makes sense with an NSDate is the second.
- Input Date = 2018-05-04 20:00:00 UTC
- localDate = 2018-05-04 13:00:00 UTC
This doesn't make sense. Why do you want "localDate" to occur 7 hours before "Input date?" You said you want to display things differently, but this says they occur at different points in time. If the goal is to display it differently, then NSDateFormatter
will do that. Just set the time zone.
If the goal is to actually change when an event occurs, then you can use dateByAddingTimeInterval:
to add or subtract the amount of time you want to adjust it by. But this has nothing to do with time zones; it moves it to a different point in the universe's history.
What are you using time_t
for in this case?
To display 2018-05-04 20:00:00 UTC as "2018/05/04 1:00 PM" in PST:
// Just creating the date. I assume you already have it, but this shows how to
// build one out of components.
NSDateComponents *comp = [NSDateComponents new];
comp.year = 2018;
comp.month = 5;
comp.day = 4;
comp.hour = 20;
comp.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
NSCalendar *gregorian = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSDate *date = [gregorian dateFromComponents:comp];
// Now format it
NSDateFormatter *form = [NSDateFormatter new];
form.timeZone = [NSTimeZone timeZoneWithName:@"PST"];
form.dateFormat = @"YYYY/MM/dd h:mm a";
NSString *string = [form stringFromDate:date]; // "2018/05/04 1:00 PM"
This said, you should always consider whether to use a localized date formatter instead. They're not always applicable, but they take care of a lot of date localization problems for you. For example:
NSDateFormatter *form = [NSDateFormatter new];
form.timeZone = [NSTimeZone timeZoneWithName:@"PST"];
form.dateStyle = NSDateFormatterShortStyle;
form.timeStyle = NSDateFormatterShortStyle;
This would output "5/4/18, 1:00 PM"
Or use a localized template:
form.dateFormat = [NSDateFormatter dateFormatFromTemplate:@"YYYY/MM/dd h:mm a" options:0
locale:[NSLocale currentLocale]];
In the US, this will be "05/04/2018, 1:00 PM", but in France it would be "04/05/2018 à 1:00 PM". Sometimes this is good, sometimes it's not what you need, but it's good to know it exists.
Upvotes: 5