Find DST (Daylight Savings Time) timestamp using Objective-C/C? - ios

Is there a way to get the specific date (way) when daylight davings begins and ends for each country using C or Objective-C?
In the Mexico, summer time begins on the first Sunday in April at 2:00am, and ends on the last Sunday in October at 2:00am. In many POSIX systems this is written as
M4.1.0/2,M10.5.0/2
(Begins: Month 4, 1st Sunday at 02:00AM, Ends: Month 10, last Sunday at 02:00AM)
I know it is possible to know if daylight savings is currently active using
NSTimeZone* systemTimeZone = [NSTimeZone systemTimeZone];
BOOL dstIsOn = [systemTimeZone isDaylightSavingTime];
and that it is possible to get the time until the next Daylight Savings begins
NSTimeZone* systemTimeZone = [NSTimeZone systemTimeZone];
NSTimeInterval delta = [systemTimeZone daylightSavingTimeOffset];
BUT: How would I go about finding the specific day that the daylight savings begins/ends?
Is there some killer table out there that I have not been able to find?
Any help would be greatly appreciated!

Yes, there is - you can use [NSTimeZone nextDaylightSavingTimeTransitionAfterDate:] method. This returns an NSDate, which you can use with daylightSavingTimeOffsetForDate to establish what the offset is.
Normally you'd use this to find the next offset, but you can obviously run it more than once with different dates to get a series of upcoming daylight saving changes. There is also a convenience method nextDaylightSavingTimeTransition which will always return the next transition.

Related

Calculate difference between 2 NSDate in year, month, day ignore time?

Giving an example, I have 2 NSDate in the same timezone UTC
NSDate *date1 = [NSDate dateWithString:#"2019-05-31 22:00:00 +0000"];
NSDate *date2 = [NSDate dateWithString:#"2019-06-01 01:00:00 +0000"];
I want to make a function to calculate difference between them in Year, month, day ignore time part. Expect result above
Year: 0
Month: 1
Day: 1
Or another example with
NSDate *date1 = [NSDate dateWithString:#"2019-02-28 22:00:00 +0000"];
NSDate *date2 = [NSDate dateWithString:#"2020-03-01 01:00:00 +0000"];
Will get result
Year: 1
Month: 13
Day: 367
I have tried answers in this question How can I calculate the difference between two dates?
But those approach using NSTimeInterval seems not reliable because of 365 or 366 days of year and does not ignore time. Answer like
NSDateComponents *components;
NSInteger days;
components = [[NSCalendar currentCalendar] components: NSDayCalendarUnit
fromDate: date1 toDate: date2 options: 0];
days = [components day];
Give wrong result too.
You could convert each NSDate value to an NSDateComponents value using NSCalendar's componentsInTimeZone:fromDate: method. This will give you the year, month and day values for your two dates, now implement your difference algorithm, which might be:
subtract the earlier date from the larger one - you can determine that based on comparing the two NSDate values
the year difference is just simple subtraction of the year components of the NSDateComponents values
the month difference is the difference between the month components, if this is negative add 12
the day difference is similar but in the negative case you have to add the length of month, which is 28, 29, 30 or 31 - figuring which is left as an exercise :-) (NSCalendar/NSDate Methods should help here)
While this guess at your required algorithm might be wrong, whatever your algorithm you should be able to implement it based on the year, month and day components. HTH
Update
So my first guess at your algorithm was wrong, my second guess is that your three differences; years, months, days; are all meant to be independent approximations of the difference in the corresponding unit. So the year difference ignores the months, days and time; the month difference ignores the days and time; and the days difference ignores the time. This is why 31 May and 1 June are "1 month" apart - the day is ignored. This guess may also be wrong of course but here is how to do it:
order you two dates so the difference is going to be positive.
get just the year, month and day components (or get them all and then discard the others) – this will discard the time component. Use one of NSCalendar's methods to do this.
your year difference is just the difference between the year components
your month difference is the difference between your month components (which could be negative) plus 12 times your year difference
your day difference can be found using components:fromDateComponents:toDateComponents:options: requesting only the day component
[Note: be careful to use the same timezone as the original dates – this is a bit fiddly as you may need to extract it from the date strings yourself (extract the +hhmm and make a time zone). You must remember that an NSDate does not store the time zone, its just an absolute point in time (so equivalent times in different times zones produce the same NSDate value) and for your calculations you want them based on the original time zone as two times one the same day in one timezone can be on different days in a different time zone...). You can set the timezone of an NSCalendar instance or use methods which take timezones when converting from NSDate to NSDateComponents]

NSTimeZone isDaylightSavingTime giving wrong value

Currently GMT-0700(US/pacific) is already in day-light-saving
But I am getting "NO" from NSTimeZone
NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:secondsFromGMT]; //Getting timezone as GMT-0700
BOOL isDaylightSavingTime = [timeZone isDaylightSavingTime]; //getting boolean value as NO
How to fix this issue?
REQUIREMENT :I want to know ,my receiver is using dayLightSavingTime or not.i will get only receiver offset value.I have to support different timezones()..What is the best approach to do this
timeZoneForSecondsFromGMT is not specific enough.
The most accurate way is to create the time zone with the (full) region name:
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:#"America/Los_Angeles"];
This is not a wrong value. You get timezone GMT-0700 but this is not a Pacific timezone. To create pacific timezone you need:
timeZone = [NSTimeZone timeZoneWithName:#"PST"];
This is short description from apple documentation:
+ (instancetype)timeZoneForSecondsFromGMT:(NSInteger)seconds;
Description Returns a time zone object offset from Greenwich Mean
Time by a given number of seconds. The name of the new time zone is
GMT +/– the offset, in hours and minutes. Time zones created with this
method never have daylight savings, and the offset is constant no
matter the date.
Other answers mentioning timeZoneWithName are correct but there's one more detail I don't think has been mentioned. The reason that timeZoneForSecondsFromGMT doesn't work is that GMT does not have daylight savings time (or summer time, as it's more sensibly called in some other countries). GMT doesn't jump forward or back; it always moves ahead by one second per second. Since you ask for a fixed number of seconds from GMT, the result also does not have GMT. If it gave you a time zone that observed daylight saving time, the number of seconds from GMT would have to change twice a year. But since you asked for a fixed number of seconds, you get a result that doesn't do that, and never reports daylight saving time in effect.

Get current date past midnight, Objective C

I want to get the current date, even if the time has passed midnight. Imagine it's friday night the 6th of June 2014 - we check the date Saturday at 2 am, but we still want this to count as being friday. How would I go about this?
Let's just say we cut it at 9am the next day. I.e. we will assume previous date until the time has passed 9 am. Yes, this is software used at a nightclub, as you can imagine.
I guess this would involve something like subtracting 1 day from the current date if the hour is less than 10?
You can use interval to specific date like
[[NSDate date] dateByAddingTimeInterval:interval];
Assuming the cutoff is 9am, all you need to do is create an NSDate that's 9 hours earlier than the actual time.
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:-(9 * 3600)];
That way every day begins and ends at 9am.

NSDate fixing timezones

I know that NSDate doesn't have timezone information.
However, I'm trying to understand how to manipulate them properly.
At the moment I'm passing a date into an object. That date is the user selected date at time 00:00:00.
i.e. if the user hits October 21st then the NSDate passed in should be. 21/10/2013 00:00:00.
However, it isn't it's 20/10/2013 23:00:00. (One hour before).
Now, this is nothing about formatting them or displaying them. I'm just using the NSDates.
I'm creating the date using NSDateComponents and NSCalendar.
I guess my question is...
How can I tell what date an NSDate is actually referring to in my local time zone?
I need to send a UNIX time stamp for 00:00:00 and 23:59:59 for a given date. However, at the moment when I set the hour, minute and second to 0, 0 and 0 then I'm not getting midnight in the current time zone I'm getting midnight in GMT.
This isn't what I want.
Fixed?
OK, I've fixed it... I think. At least, it's doing what I want it to do.
The trick is...
NSTimeZone *timeZone = [NSTimeZone localTimeZone];
[dateComponents setSecond:timeZone.secondsFromGMT];
I've been confused by this many times. When you NSLog an NSDate, you'll always get the output in GMT. So the 20/10/2013 23:00:00 (GMT) you're seeing is the same as your expected 21/10/2013 00:00:00 (BST). The UNIX timestamp for both of these dates would be the same because it doesn't take into account timezone - it's always UTC.
If you want to output in a user-readable format, an NSDateFormatter will format the date using your current timezone and locale.

System timezone vs selected timezone

What's the best way to compare two time zones?
I'm facing an issue while comparing two NSTimeZone instances using - (BOOL)isEqualToTimeZone:(NSTimeZone *)aTimeZone method.
NSString *timeZoneName = ...
NSTimeZone *sytemTimeZone = [NSTimeZone systemTimeZone];
NSTimeZone *selectedTimeZone = [NSTimeZone timeZoneWithName:timeZoneName];
if ([sytemTimeZone isEqualToTimeZone:selectedTimeZone])
isEqual = YES;
else
isEqual = NO;
Step 1: Go to Settings (Application) > General > Date & Time > Time Zone and search for "Austin". The entry that you'll get will be "Austin, U.S.A". Select this Time Zone. This SHOULD be your new system time zone now!
Step 2: Create a small iPhone/iPad application. Use [NSTimeZone knownTimeZoneNames] to get a list of time zone names. Then try to find "Austin". It's not there! So, i guess we can use "America/Chicago" as the timezone?
Why is the Setting's timezone list different from ours?
Step 3: Now compare the system timezone with time zone for "America/Chicago". They don't match.
I've posted a bug for this - The bug is that Austin isn't in the known time zone list yet is offered by the settings app.
As per an Apple Engineer:
For two NSTimeZones to compare equal, both the names and the data (as
returns by -data) must be equal. You have to be careful when
comparing time zones, because two zones can have the same offset from
GMT but not be the same time zone for historical reasons. Remember
that time zones are used for all sorts of calendrical calculations,
meaning that they are only equal if, throughout history, they've
always had the same GMT offset, the same daylight savings transitions,
and so on.

Resources