(Obj-c) Identify morning, afternoon or night from a date string - ios

I'm working in Objective-C. I have this three values in string, which they determine the part of the day
NSString *morning = #"7:01";
NSString *afternoon = #"12:01"
NSString *night = #"19:01"
And my original date is this, also in String
NSString *currentTime = #"Sat, 17 Oct 2015 9:58 am CDT"
I need to identify if the current date is morning, afternoon or night according with the current date as String. Anyone have a solution?

Your question has received a negative score (-4 at the time of writing) as people obviously feel you haven't shown the effort SO expects. However your question hides a gotcha and something which Apple recently made harder, which makes it interesting.
Your sample time is:
NSString *currentTime = #"Sat, 17 Oct 2015 9:58 am CDT"
which would seem to be "morning". However this is exactly the same time as:
Sat, 17 Oct 2015 2:58 pm GMT
which would seem to be "afternoon". Both these times are:
Sat, 17 Oct 2015 14:58 UTC
Why is this an issue?
An NSDate is a point in time without any associated time zone. The class NSDateFormatter, and associated methods on NSDate itself, will parse a date-time string and produce the absolute UTC point in time the string represents. Any time zone in the string, such as CDT in the example, is allowed for in determining the absolute time point but is not directly represented in the NSDate value that results.
When the NSCalendar class is used to break out the parts of a date it does so in relation to a time zone, which defaults to the system time zone.
What all this adds up to is if your app is running, say, on a computer in the UK and you follow the suggestion in the comments:
parse the time (using NSDateFormatter)
break out the hour & min to get an NSDateComponents value (using NSCalendar); and
compare the hour & min to your boundaries then your sample time will be reported as "afternoon"
Not good :-(
What you need is to parse the date-time (getting a standard UTC time point) and the time zone, you can then pass that time zone to NSCalendar and the rest is easy.
Apple makes it harder
Prior to OS X 10.9 & iOS 7 the NSDateFormatter class returned an NSCalendarDate date value, that type was a subclass of NSDate and also stored an NSTimeZone value. So parsing your sample returned both the time point "Sat, 17 Oct 2015 14:58 UTC" and the time zone "UTC-5". With that information NSCalendar could be used to break out the hour & min and correctly determine the time is "morning".
NSCalendarDate is now deprecated, and while it is still possible to use it this could change at any moment. Apple do not yet appear to have provide an alternative "parse date and time zone" method.
Parsing both the date and time zone offset
From the simple observation that if you parse "Sat, 17 Oct 2015 9:58 am CDT" ignoring the time zone and treating it as UTC the result is an absolute time point which differs by 5 hours, the time zone offset for CDT, from the one obtained if the string is parsed taking the time zone into account you have a method to obtain the time zone - parse the string twice, once ignoring the time zone, and determine the difference.
This may not be the best algorithm, but it does work... (you may insert here warnings about premature optimisation!)
So here goes (minimal comments, look the methods up in the documentation, error checking etc. - treat as an outline only):
- (BOOL) dateAndZoneFromString:(NSString *)timeString // the date-time string
dateFormat:(NSString *)dateFormat // the format of the date-time, should contain a time zone format at the end
parsedDate:(NSDate **)date // NSDate representing the absolute time point
parsedZone:(NSTimeZone **)zone // NSTimeZone representing the time zone of the original string
error:(NSError **)error
{
NSDateFormatter *df = [NSDateFormatter new];
// parse timeString taking time zone into account
df.dateFormat = dateFormat;
NSDate *absDate = [df dateFromString:timeString];
// parse timeString ignoring the time zone by removing the format specifier from dateFormat
df.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"UTC"];
df.dateFormat = [dateFormat stringByReplacingOccurrencesOfString:#" *[zZvV]+$" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, dateFormat.length)];
NSDate *zonelessDate;
NSRange range = NSMakeRange(0, timeString.length);
if ( [df getObjectValue:&zonelessDate forString:timeString range:&range error:error] )
{
// parse successful, calculate the difference and construct an NSTimeZone value
NSTimeInterval offset = [zonelessDate timeIntervalSinceDate:absDate];
NSTimeZone *timezone = [NSTimeZone timeZoneForSecondsFromGMT:offset];
*date = absDate;
*zone = timezone;
return YES;
}
else
return NO;
}
If you pass #"Sat, 17 Oct 2015 9:58 am CDT" and for format #"E, d MMM y h:m a z" to this method it will return the time point "Sat, 17 Oct 2015 14:58 UTC" as an NSDate and the time zone "UTC-5" as an NSTimeZone.
If you pass #"Sat, 17 Oct 2015 2:58 pm GMT" then it will return the same absolute time point and a time zone of "UTC+0".
For this point you can use these values with NSCalendar, NSDateComponents, and simple comparisons to determine morning/afternoon/night.
HTH

-(void)ShowTimeMessage
{
// For calculating the current date
NSDate *date = [NSDate date];
// Make Date Formatter
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh a EEEE"];
// hh for hour mm for minutes and a will show you AM or PM
NSString *str = [dateFormatter stringFromDate:date];
// NSLog(#"%#", str);
// Sperate str by space i.e. you will get time and AM/PM at index 0 and 1 respectively
NSArray *array = [str componentsSeparatedByString:#" "];
// Now you can check it by 12. If < 12 means Its morning > 12 means its evening or night
NSString *message;
NSString *timeInHour;
NSString *am_pm;
NSString *DayOfWeek;
if (array.count>2)
{
// am pm case
timeInHour = array[0];
am_pm = array[1];
DayOfWeek = array[2];
}
else if (array.count>1)
{
// 24 hours case
timeInHour = array[0];
DayOfWeek = array[1];
}
if (am_pm)
{
if ([timeInHour integerValue]>=4 && [timeInHour integerValue]<=9 && [am_pm isEqualToString:#"AM"])
{
message = [NSString stringWithFormat:#"Morning"];
}
else if (([timeInHour integerValue]>=10 && [timeInHour integerValue]!=12 && [am_pm isEqualToString:#"AM"]) || (([timeInHour integerValue]<4 || [timeInHour integerValue]==12) && [am_pm isEqualToString:#"PM"]))
{
message = [NSString stringWithFormat:#"Afternoon"];
}
else if ([timeInHour integerValue]>=4 && [timeInHour integerValue]<=9 && [am_pm isEqualToString:#"PM"])
{
message = [NSString stringWithFormat:#"Evening"];
}
else if (([timeInHour integerValue]>=10 && [timeInHour integerValue]!=12 && [am_pm isEqualToString:#"PM"]) || (([timeInHour integerValue]<4 || [timeInHour integerValue]==12) && [am_pm isEqualToString:#"AM"]))
{
message = [NSString stringWithFormat:#"Night"];
}
}
else
{
if ([timeInHour integerValue]>=4 && [timeInHour integerValue]<10)
{
message = [NSString stringWithFormat:#"Morning"];
}
else if ([timeInHour integerValue]>=10 && [timeInHour integerValue]<16)
{
message = [NSString stringWithFormat:#"Afternoon"];
}
else if ([timeInHour integerValue]>=16 && [timeInHour integerValue]<22)
{
message = [NSString stringWithFormat:#"Evening"];
}
else
{
message = [NSString stringWithFormat:#"Night"];
}
}
if (DayOfWeek)
{
_timeLbl.text=[NSString stringWithFormat:#"%# %#",DayOfWeek,message];
}
}

Related

how to convert date according to time zones

So in my project a user from USA set some time say it was 10:30 am
and now when a person some another country see that time then it should be according to their timezone .
For Example in USA it is 5:30 am now
and in india it is 6:30 pm , so if after 5 hours a person in india sees that then that person should see 6:30 pm for that post
Use php function gmdate()
string gmdate(string $format[,int $timestamp= time()] )
Identical to the date()function except that the time returned is Greenwich Mean Time (GMT).
Parameters format The format of the outputted date string. See the formatting options for the date() function. timestamp The optional timestamp parameter is an integer Unix timestamp that defaults to the current local time if a timestamp is not given. In other words, it defaults to the value of time().Return Values Returns a formatted date string. If a non-numeric value is used for timestamp, FALSE is returned and an E_WARNING level error is emitted.
in timestamp add the interval to.
Ex if GMT zone is 5 say then add timestamp+5*60*60
Use below function:
class func getDateWithFormat(format: String) -> NSDate {
var dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone()
dateFormatter.dateFormat = format
var newDate: NSDate = dateFormatter.dateFromString(dateFormatter.stringFromDate(NSDate()))
return newDate
}
Eg: var todaysDate: NSDate = NSDate.getDateWithFormat("dd:mm:yyyy hh:mm:ss a")
I created the below function to solve this problem.
How it works: suppose this was your local time converted to GMT zero - 2016-04-14 21:00:00 +0000
and when I convert it using following function, I'm here in New Delhi India, which has GMT+05:30, then I will get time 2:30 of morning.
+(NSString*)getLocalTimeFromGMTzero : (NSString*)GMTzerioTimeString {
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"yyyy-MM-dd HH:mm"];
//Create the date assuming the given string is in GMT
df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
NSDate *date = [df dateFromString:GMTzerioTimeString];
//Create a date string in the local timezone
df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:[NSTimeZone localTimeZone].secondsFromGMT];
NSString *localDateString = [df stringFromDate:date];
NSLog(#"date = %#", localDateString);
return localDateString;
}

Issues in converting date string (any time zone) to NSDate of French Time Zone

I want to convert a date string (can be in any time zone) to a date in French Time Zone. I am using following code.
NSString * dateString = #"27/05/2015 - 19:00" // system time zone is GMT +5
NSDateFormatter* frenchDateFormatter = [[NSDateFormatter alloc] init];
[frenchDateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
[frenchDateFormatter setDateFormat:#"dd/MM/yyyy - HH:mm"];
NSDate *frenchDate = [frenchDateFormatter dateFromString:dateString];
NSLog(#"%#",frenchDate);
NSString * frenchString = [frenchDateFormatter stringFromDate:frenchDate];`
Elaboration
--> System time zone is GMT +5
--> French time zone is GMT +2
Date string = 27/05/2015 - 19:00
Expected result = 27/05/2015 - 16:00
Actual result (NSDate) = 2015-05-27 17:00:00 +0000
Actual result (NSString from date) = 27/05/2015 - 19:00
Kindly point out if I am missing something
If you use NSLog to display dates it'll be displayed in UTC. So either you have to convert in your head, or don't use it. I wrote a long answer explaining this to a different question.
Because you have set the timezone of your parsing dateFormatter to Paris the string you parse is treated as "time in paris". That's your problem, you actually wanted to parse it in local time.
The results you get are exactly as one would expect.
You create a NSDate that relates to "19:00 in Paris". Since Paris is UTC+2 that date is 17:00 in UTC (or in +0000). If you convert that date back to "time in Paris" you end up with the same string as before.
If you want to convert the representation of a point in time in your location to a different representation at a different location you have to use two dateFormatters.
NSString *localDateString = #"27/05/2015 - 19:00" // system time zone is GMT +5
NSDateFormatter* localDateFormatter = [[NSDateFormatter alloc] init];
[localDateFormatter setTimeZone:[NSTimeZone localTimeZone]];
[localDateFormatter setDateFormat:#"dd/MM/yyyy - HH:mm"];
NSDate *date = [localDateFormatter dateFromString:localDateString]; // date contains point in time. It no longer has a timezone
NSDateFormatter* franceDateFormatter = [[NSDateFormatter alloc] init];
[franceDateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Paris"]];
[franceDateFormatter setDateFormat:#"dd/MM/yyyy - HH:mm"];
NSString * timeInFranceString = [franceDateFormatter stringFromDate:date]; // representation of the point in time from above for people in Paris
This line prints out the date/time in GMT, as it calls [NSDate description], and there is a potential difference between systemTimeZone and GMT, hence the difference you are seeing:
NSLog(#"%#",currentDate);
If you want to see what the date/time is for a particular timezone then use the NSDateFormatter object to get the string.
A date doesn't have a time zone information. A date is internally represented as a number. We don't have to know anything about that number (it's a number of seconds from a fixed date in UTC), the important thing is to understand that to display a date to a user, you have to convert it to a string first.
A string representation of a number is generated from a date using a date format and a time zone. For all date -> string and string -> date conversions you can use NSDateFormatter.
You have successfully parsed currentDate from your string representation. If you want to reverse the process and get the string representation, just use [currentDateFormatter stringFromDate:currentDate]
Check at http://www.timeanddate.com/worldclock/
Right now Paris is two hours ahead of UTC. The result is absolutely correct. NSDate keeps dates in UTC. The idea is that if any two people look at their watch at the same moment, and convert the time they see on their watch to NSDate, they will get the same result.
You cannot get an NSDate for a timezone. NSDate doesn't support time zones. The only way to get a date with a time zone is to use NSDateFormatter to convert it to a string.

Unix time stamp received from server using EEST timezone

In my application i request certain date field from my server, the server returns values like :2014-06-03 00:00:00 EEST , but i need to load that data using GMT(GMT+2…) format, i am using the following code :
double unixTimeStamp = [[date objectAtIndex:indexPath.row] doubleValue];
NSTimeInterval _interval=unixTimeStamp;
NSDate *dateToFinal = [NSDate dateWithTimeIntervalSince1970:_interval];
NSDateFormatter *_formatter=[[NSDateFormatter alloc]init];
_formatter.dateFormat = #"yyyy-MMMM-dd HH:mm:ss zzz";
[_formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:[[NSUserDefaults standardUserDefaults] objectForKey:#"timeZone"]] ];
[_formatter setDateFormat:#"dd MMMM yyyy"];
dateFinal=[_formatter stringFromDate:dateToFinal];
// NSLog(#"Date Time < 3 %#" , dateFinal);
the user has the possibility to change his timezone, that's why when he saves it it's stored in a local cached variable , which i call in the previous code. But the most weird part is , if the user changes to GMT +1 or +2 or whatever, the application would still output the same hour time, which is 00:00, but if he changes to anything different from GMT, it will change. It's not normal to have GMT,GMT+1,GMT+4… to output the same hour which is 00:00. As a unix timestamp example we have 1401742800, which if u use an online time converter you would get Mon, 02 Jun 2014 21:00:00 GMT , but in the app its neither the same date nor time…what am i missing ?

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.

How to insert an NSDate into a column in an Azure managed database?

If you have an Azure back-end, with a column that is a DateTime or DateTimeOffset, the example code is rather sparse about how you send a timestamp value as part of an insert.
You can pass along an NSDate in the dictionary of values to insert, and the library will translate it for you and insert is as a UTC/GMT timezone value. However, my client specifically wanted this value to be in the timezone of the device which generated the data, which means I need to insert the value as a string, since NSDate has no inherent knowledge of timezones.
So...any suggestions on how to write the NSDate-to-string method?
How about this:
I changed my Azure Sql column datatype to datetimeoffset (which internally stores values as UTC as well as the timezone offset).
On client side I then used a date format with five Z's:
let date = NSDate() // local date time: Jun 27, 2014, 9:32 AM
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" // Note 5 Z's...
let strNow = formatter.stringFromDate(date) // "2014-06-27T09:32:49+02:00"
I was then able to insert the date string "2014-06-27T09:32:49+02:00" to my Azure table in that format.
Querying my Azure table for that same inserted date I received back:
2014/06/27 09:32:49 +02:00
There are two "gotchas":
The format is very specific for Azure to recognize and parse it correctly.
The required format is non-standard: the 'Z' specifier produces a timezone offset such as -0700 or +0800 but Azure will reject it if there isn't a colon between the hours and minutes, ie, -07:00 or +08:00. In the ARC solution below the colon is inserted after the string is generated.
(weird - format is a little off?)
+(NSString*)azureDateTimeString:(NSDate *)date
{
static NSDateFormatter *df = nil;
if(df == nil)
{
df = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] ;
[df setLocale:enUSPOSIXLocale];
df.timeZone = [NSTimeZone localTimeZone];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZ"];
}
NSString *dateString = [df stringFromDate:date];
// insert a colon in the third position from the right of the string...
NSString *newString = [NSString stringWithFormat:#"%#:%#", [dateString substringToIndex:[dateString length]-2], [dateString substringFromIndex:[dateString length]-2]];
return newString;
}
In my case I found I had to append "Z" as a literal suffix rather than a timezone type indicator as part of the format string:
(My Azure column is DateTime and I'm using Xcode Swift)
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
let strNow = formatter.stringFromDate(date)
= "2014-06-27T00:40:52Z"
Note that I not only included 'T' as a literal but also 'Z'.
I could then successfully insert that date string into my Azure table and then, as a test, I could read it back and reverse it like this:
var creationDate = "2014-06-27T00:40:52Z"; //read back from azure table
let dtCreation = formatter.dateFromString(creationDate)
= Jun 27, 2014, 12:40 AM"

Resources