How to offset NSDate with UTC timezone offset without hardcoded manual calculation - ios

Imagine the current local time being 15:11 UTC. I retrieve a data set from the server showing the opening closing time of a business displayed like so:
{
close = {
day = 3;
time = 0200;
};
open = {
day = 2;
time = 1700;
};
I also receive a utc-offset property exposed like so: "utc_offset" = "-420”; which I imagine is a minute offset giving an hour offset of 7 hours which seems right considering the timezone I'm in is UTC and the business location's opening hours information I'm receiving is for a business in Los Angeles who are 7 hours behind.
How do I use this property to then be able to do any time calculations on it
I want to determine whether the current local time falls between the open and close time that bit I have figured out but the calculations come out wrong considering the time comparison is done in the local timezone when it needs to be offset before calculating against that time range.
I'm trying to avoid doing things like
Psuedocode:
NSDate.date hour componenent + (UTC_offset / 60 = -7 hours)
Update:
Here's how I'm currently checking if the business is open right now
if currentArmyTime.compare(String(openInfo.time)) != .OrderedAscending && currentArmyTime.compare(String(closeInfo.time)) != .OrderedDescending {
//The business is open right now, though this will not take into consideration the business's time zone offset.
}
Is it easier to offset the current time?

Before you can use the 'open' and 'close' times in date operations you need to create an NSDate from a calendar that has been set to the time zone for those times. Here's an example:
// Create calendar for the time zone
NSInteger timeOffsetInSeconds = -420 * 60;
NSTimeZone *tz = [NSTimeZone timeZoneForSecondsFromGMT:timeOffsetInSeconds];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
calendar.timeZone = tz;
// Create an NSDate from your source data
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = 1;
comps.month = 1;
comps.year = 2016;
comps.hour = 8;
comps.minute = 0;
NSDate *openTime = [calendar dateFromComponents:comps];
// 'openTime' can now be to compared with local time.
NSLog(#"openTime = %#", openTime); // Result is openTime = 2016-01-01 15:00:00 +0000
You should put the above code into a method that takes in the raw time and the time offset to apply.

Related

Is there a way to detect which millennium a NSDate is in?

I have an NSDate from a string of 01/01/14. Unfortunately the strings are saved with two digits so I have no idea if the year is from 1900's or 2000's. But I want create some intelligent code to guess what millennium and century the full year is. I know for a fact (based on the application I'm creating) that the year can't be below 1900 in 99% of cases.
I have converted the date to now show four digits on but it's now being displayed as 01/01/0014.
Is there a way to detect the millennium of the NSDate as 0 and make my changes accordingly?
What I really want to do is something like this (pseudo code):
if (millennium == 0 && decade < 15 && decade > 99)
{
millennium = 2;
century = 0;
// change the date to 2000's here
}
else if (millennium == 00)
{
millennium = 1;
century = 9;
// change the date to 1900's here
}
For starters your pseudocode isn't quite right (the first if statement is an impossible condition as decade can't be less than 15 and more than 99 at the same time).
I have created a basic solution using NSDateComponents and made up my own conditions for when to change the year which you can easily change.
NSDate *date; // this is your date
NSDateComponents* components = [[NSCalendar currentCalendar] components: NSMonthCalendarUnit | NSDateCalendarUnit | NSYearCalendarUnit fromDate:date];
if([components year] < 15) // 2000 to 2015
{
[components setYear:[components year] + 2000];
}
else if([components year] < 100) // 1915 to 1999
{
[components setYear:[components year] + 1900];
}
date = [NSCalendar currentCalendar] dateFromComponents:components];
there is an oldschool stuff (from the 80s) here to convert a year in 2 digits to year in 4 digits.
int finalYear = (19 + (yearIn2Digits < 50)) * 100 + yearIn2Digits;
then you can use that finalYear value to build up the proper NSDate object.
the covered interval is always 100 years and it is up you where you'd like to draw the line. the original idea worked between 1950 and 2049 – as you see in the formula, – but you can refine it for covering better your actual bounds of years.
I wouldn't recommend hardcoding this logic.
what if you want to convert a date which is 1908 , or 2015.
A smarter way to do this is as follows :
-(BOOL)isInCurrentDecade:(NSDate*)date{
// I don't recollect the api to extract year from NSDate
NSInteger tmpYear = [date year];
NSInteger currentYear = [[NSDate date] year];
return tmpYear > currentYear%100
}
What I am doing here is that I compare 87 , 04 , 99 with current year digit's 14. and if it's between 00 and now then its current decade. This code is more robust than your's because it's relative comparison with current date
o/p of the code is as follow as of year 2014 :
87 - > NO // in 90's
99 -> NO
04 - > YES // in 2000's
12 - > YES
Edge case occurs when your date includes 1/1/14 if you want it to be filtered in current decade replace the '>' with ' >=" .
Use NSDateFormatter and its property "twoDigitStartDate". You set this to the earliest date that you want to be able to enter with a two digit year. No complicated logic needed, and easy to update. Now data entry is one thing, but storing a date "with a two digit year", that's criminal.
And it handles things like "I want to be able to store anything starting with the start of the tax year 1985 in two digits, that is April 1st 1985". Then April 1st 85 will be in 1985, while March 31st 85 will be in 2085. With no effort.

Wrong systemTimeZone

I'm trying to get systemTimeZone, but it gives me wrong data:
NSTimeZone * currentDateTimeZone = [NSTimeZone systemTimeZone];
NSString* name = [currentDateTimeZone name];
int myGMT = (int)roundf([currentDateTimeZone secondsFromGMT]/60.f/60.f);
I'm living in Budapest,Hungary. It's in GMT+1, but I'm getting myGMT = 2.
But name is ok : name = Europe/Budapest
Why?
The current GMT offset for the Europe/Budapest timezone is GMT+2, because
the Daylight Saving Time started at Sunday, 30 March 2014, and the clocks were
advanced by one hour (see http://www.timeanddate.com/worldclock/city.html?n=50).
You can verify that with
BOOL isDst = [currentDateTimeZone isDaylightSavingTime];
// --> YES
NSTimeInterval dstOffset = [currentDateTimeZone daylightSavingTimeOffset];
// --> 3600
If necessary, you can compute
[currentDateTimeZone secondsFromGMT] - [currentDateTimeZone daylightSavingTimeOffset]
to get the "default" GMT offset for your timezone.

Compare time (in format HH:MM:SS) if between two times in IOS

I have the start time and end time in formats HH:mm:ss (24-hour).
I need to compare if the current time is between the start and end time.
I have coded the logic in such a way that it will add 24 hrs to the start time if start time is later than the end time.
if (shift.sShiftStart < shift.sShiftEnd) {
startTime = shift.sShiftStart;
startTimeInt = [[shift.sShiftStart substringToIndex:2] integerValue];
startTimeInt2 = startTimeInt + 24;
finalStartTime = [startTime stringByReplacingCharactersInRange:NSMakeRange(0, 2) withString:[NSString stringWithFormat:#"%d", startTimeInt2]];
} else {
finalStartTime = shift.sShiftStart;
}
Now I want to check if my currentTime is between finalStartTime and endTime (all are in HH:mm:ss formats)
Convert the strings to dates (NSDate) and use the compare: method. Don't assume that you can use < on object instances and they will magically know what you want them to do with that (you're actually comparing the pointer values).
Once you have the dates you can add time (also look at the NSDateComponents class).

Getting date from weekday

I'm doing this app where the user inputs some days (Using UITableView, monday - sunday).
I then need the app to figure out which dates this matches with. Say it's the user sits on sunday the 15th and chooses monday and tuesday. The app will figure out the dates are monday 16th and tuesday 17th.
How would one go about that using NSDate and such? I know how to find a weekday using the date, but I want the opposite.
Of course it has to be the closest days, like not finding monday the 23rd, but finding 16th.
Hope that makes sense. :-)
A direct method, without using a loop:
NSUInteger targetWeekday = ...; // 1 = Sunday, 2 = Monday, ...
// Date components for today:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDateComponents *comp = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit
fromDate:now];
// Adjust components for target weekday:
if (targetWeekday >= comp.weekday) {
comp.day += (targetWeekday - comp.weekday);
} else {
comp.day += (targetWeekday + 7 - comp.weekday); // Assuming 7 days per week.
}
comp.weekday = targetWeekday;
// And back to NSDate:
NSDate *targetDate = [cal dateFromComponents:comp];
Remark:
if (targetWeekday >= comp.weekday) {
comp.day += (targetWeekday - comp.weekday);
} else {
comp.day += (targetWeekday + 7 - comp.weekday); // Assuming 7 days per week.
}
can be replaced by the shorter, equivalent code
comp.day += (targetWeekday + 7 - comp.weekday) % 7;
You can do it by following a simple procedure:
Start with an NSDate that represents today
Get the day of the week from it (here is how it is done)
If the day of the week matches what's in the selected UITableViewCell, you are done.
Otherwise, add one day to NSDate (here is how it is done), and go back to step 2.

How to show date with timezone for date, relevantly to defined country/zone?

I need to show a date in concrete time zone including DST (European time). App will be used in Lithuania, so time zone is +3 at summer and +2 at other time. The thing is, I have just a list of dates and I don't know how to show +3 for summer dates and +2 for other dates. Currently, I have time zones:
// Eastern European Summer Time UTC + 3 hours
NSTimeZone *timeZoneWithDst = [NSTimeZone timeZoneWithAbbreviation:#"EEST"];
//Eastern European Time UTC + 2 hours
NSTimeZone *timeZoneWithoutDst = [NSTimeZone timeZoneWithAbbreviation:#"EET"];
But how to loop through my list of dates and calculate should I add +3 or +2 to date?
UPDATE Finally I got it working by applying Martin R. suggestion to use time zone by name, not by abbreviation. In this way, date with this time zone handles DST automatically. Here's my code for converting dates:
NSTimeZone *TimeZone = [NSTimeZone timeZoneWithName:#"Europe/Vilnius"];
NSInteger seconds = [myTimeZone secondsFromGMTForDate:someDate];
NSDate *result = [NSDate dateWithTimeInterval:seconds sinceDate:someDate];
To convert an NSDate to a string representation, use NSDateFormatter. By default, it uses the local time zone. To display the date according to a concrete time zone, you can set
NSTimeZone *tz = [NSTimeZone timeZoneWithName:#"Europe/Vilnius"];
[dateFormatter setTimeZone:tz];
(According to http://www.timezoneconverter.com/cgi-bin/findzone, the time zone for Lithuania is "Europe/Vilnius".)
This is a very similar alternative that worked for me, in Swift:
var currentDate: NSDate {
let currentLocalTime = NSDate()
let localTimeZone = NSTimeZone.systemTimeZone()
let secondsFromGTM = NSTimeInterval.init(localTimeZone.secondsFromGMT)
let resultDate = NSDate(timeInterval: secondsFromGTM, sinceDate: currentLocalTime)
return resultDate
}

Resources