This question already has an answer here:
sethours in NSDateComponents
(1 answer)
Closed 9 years ago.
I am trying to create a date with the time set to 12:00:01 am. Seconds and minutes set to their values correctly but the hour value always goes to whatever i set the value, + 4. Why 4? What is so special about that value? The minute and second values set to what I want correctly but it appears the hours value simply adds rather than replaces.
here is the code,
NSDate *now = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:now];
[components setHour:0];
[components setMinute:0];
[components setSecond:1];
NSDate *compareTime = [calendar dateFromComponents:components];
NSLog(#"compareTime: %#", compareTime);
NSLog(#"currentTime: %#", now);
output is :
compareTime: 2013-05-17 04:00:01 +0000
currentTime: 2013-05-17 15:00:37 +0000
EST is 4 hours ahead of GMT, hence your offset. Here's some code we use to create dates plus and minus the current time in the local time zone.
- (NSDate *) getDateWithHoursOffset : (int) aHourInt
{
CFGregorianDate gregorianStartDate, gregorianEndDate;
CFGregorianUnits startUnits = { 0,0,0, aHourInt,0,0 }; //2 hours before
CFGregorianUnits endUnits = { 0,0,0, 8,0,0 }; //5 hours ahead
CFTimeZoneRef timeZone = CFTimeZoneCopySystem();
gregorianStartDate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeAddGregorianUnits(CFAbsoluteTimeGetCurrent(), timeZone, startUnits),timeZone);
gregorianStartDate.minute = 0;
gregorianStartDate.second = 0;
gregorianEndDate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeAddGregorianUnits(CFAbsoluteTimeGetCurrent(), timeZone, endUnits),timeZone);
gregorianEndDate.minute = 0;
gregorianEndDate.second = 0;
NSDate* startDate = [NSDate dateWithTimeIntervalSinceReferenceDate:CFGregorianDateGetAbsoluteTime(gregorianStartDate, timeZone)];
CFRelease(timeZone);
return startDate;
}
NSDates exist independently of timezones. If you need the date to display 12:00:01 in the application, you should use a NSDateFormatter.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterFullStyle];
NSLog(#"formattedTime: %#", [dateFormatter stringFromDate:compareTime]);
This returns:
formattedTime: 12:00:01 AM Central Daylight Time
The problem is that your dates are correct but they're being logged in UTC relative to your device's time zone and that seems confusing. (It is, at first)
Your compare time is correct. It is set to midnight your time and outputted as UTC and if you're EST midnight would be 4am UTC:
compareTime: 2013-05-17 04:00:01 +0000
Current time is also correct, and again it is UTC time relative to your device's time zone:
currentTime: 2013-05-17 15:00:37 +0000
Your times are correct, its the output that is deceiving you.
This code (shamefully stolen from a thread listed below) should output compareTime's UTC date as 00:00:01 +0000. Though for date calculations UTC should be fine.
NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;
NSDate* destinationDate = [[NSDate alloc] initWithTimeInterval:interval sinceDate:compareTime];
Here are a few S.O. threads to help further explain:
Does [NSDate date] return the local date and time?
Why isn't my time zone being saved into my NSDate?
NSDate is not returning my local Time zone /default time zone of device
Related
I am trying to find how many milliseconds into the current day we are. I can't find a method to return the time in milliseconds ignoring date, so I figured I could calculate it off of the value returned by timeIntervalSince 1970 method.
I did this:
NSLog(#"%f", [[NSDate date] timeIntervalSince1970]);
2013-05-21 16:29:09.453 TestApp[13951:c07] 1369171749.453490
Now my assumption is that, since there are 86,400 seconds in a day I could divide this value by 86400 and get how many days have elapsed since 1970. Doing this gives me 15846.8952483 days. Now, if my assumption holds, I am 89.52483% through the current day. So multiple 24 hours by 86.52659% would give me a current time of the 21.4859592 hour or about 09:29 PM. As you can see from my NSLog this is about 5 hours from the real time, but I believe the interval returned is GMT so this would be 5 hours ahead of my time zone.
So I figured, well what the heck, I'll just roll with it and see what happens.
I cut off the decimal places by doing:
float timeSince1970 = [[NSDate date] timeIntervalSince1970]/86400.0;
timeSince1970 = timeSince1970 - (int)timeSince1970
Then calculate the milliseconds that have taken place thus far today:
int timeNow = timeSince1970 * 86400000;
NSLog(#"%i", timeNow);
2013-05-21 16:33:37.793 TestApp[14009:c07] 77625000
Then I convert the milliseconds (which still seem appropriate) to NSDate:
NSString *timeString = [NSString stringWithFormat:#"%d", timeNow];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"A"]
NSDate *dateNow = [dateFormatter dateFromString:timeString];
NSLog(#"%#", dateNow);
2013-05-21 16:29:09.455 TestApp[13951:c07] 2000-01-02 03:29:00 +0000
And there is my problem. Rather than returning a 2000-01-01 date with some hours and minutes attached, it is returning a 2000-01-02 date. Why!?
EDIT
I got it working by "removing" the extra 5 hours I noted in the above with:
int timeNow = (timeSince1970 * 86400000) - (5 * 60 * 60 * 1000);
I don't understand why this is necessary though. If someone can explain I'd greatly appreciate it.
EDIT 2
Perhaps I should be asking a more elementary question about how to accomplish the task I'm trying to accomplish. I care about times (for example, 4pm is important but I could care less about the date). I've been storing these in NSDates created by:
[dateFormatter setDateFormat:#"hh:mm a"];
[dateFormatter dateFromString#"04:00 PM"];
All this seems to be going fine. Now I want to compare current time to my saved time and find out if it is NSOrderedAscending or NSOrderedDescending and respond accordingly. Is there a better way to be accomplishing this?
You need to use NSCalendar to generate NSDateComponents based on right now, then set the starting hour, minute, and second all to 0. That will give you the beginning of today. Then you can use NSDate's -timeIntervalSinceNow method to get back the time elapsed between now and your start date.
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
// BUILD UP NSDate OBJECT FOR THE BEGINNING OF TODAY
NSDateComponents *comps = [cal components: (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate: now];
comps.hour = 0;
comps.minute = 0;
comps.second = 0;
// USE CALENDAR TO GENERATE NEW DATE FROM COMPONENTS
NSDate *startOfToday = [cal dateFromComponents: comps];
// YOUR ELAPSED TIME
NSLog(#"%f", [startOfToday timeIntervalSinceNow]);
Edit 1
If you're just looking to compare some NSDateObjects you can see if the time interval between then and now is negative. If so, that date is in the past.
NSDate *saveDate = [modelObject lastSaveDate];
NSTimeInterval difference = [saveDate timeIntervalSinceNow];
BOOL firstDateIsInPast = difference < 0;
if (firstDateIsInPast) {
NSLog(#"Save date is in the past");
}
You could also use compare:.
NSDate* then = [NSDate distantPast];
NSDate* now = [NSDate date];
[then compare: now]; // NSOrderedAscending
The part of your question that says that you want to calculate "how many milliseconds into the current day we are" and then "4pm is important but I could care less about the date" makes it not answerable.
This is because "today" there could have been a time change, which changes the number of milliseconds since midnight (by adding or subtracting an hour, for instance, or a leap second at the end of a year, etc....) and if you don't have the date, you can't determine the number of milliseconds accurately.
Now, to address your edited question: If we assume today's date, then you need to use the time that you have stored and combine it with today's date to get a "specific point in time" which you can compare to the current date and time:
NSString *storedTime = #"04:00 PM";
// Use your current calendar
NSCalendar *cal = [NSCalendar currentCalendar];
// Create a date from the stored time
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:#"hh:mm a"];
NSDate *storedDate = [dateFormatter dateFromString:storedTime];
// Break it up into its components (ie hours and minutes)
NSDateComponents *storedDateComps = [cal components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:storedDate];
// Now we get the current date/time:
NSDate *currentDateAndTime = [NSDate date];
// Break it up into its components (the date portions)
NSDateComponents *todayComps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:currentDateAndTime];
// Combine with your stored time
todayComps.hour = storedDateComps.hour;
todayComps.minute = storedDateComps.minute;
// Create a date from the comps.
// This will give us today's date, with the time that was stored
NSDate *currentDateWithStoredTime = [cal dateFromComponents:todayComps];
// Now, we have the current date and the stored value as a date, so it is simply a matter of comparing them:
NSComparisonResult result = [currentDateAndTime compare:currentDateWithStoredTime];
it is returning a 2000-01-02 date. Why!?
Because your dateFormatter uses the current system locale's timezone.
If you insert ...
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
... your date formatter will interpret the string correctly. But why not creating the date directly:
NSDate *dateNow = [NSDate dateWithTimeIntervalSinceReferenceDate:timeNow];
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iPhone - get number of days between two dates
I am trying to compare 2 dates and find out the number of day in between them.
something like below:
now = [NSDate date];
// This is i am saving in NSUSerdefault on some condition,like
if (a == 1) {
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:MM:SS";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSLog(#"The Current Time is %#",[dateFormatter stringFromDate:now]);
datesaved = [NSString stringWithFormat:#"%#",[dateFormatter stringFromDate:now]];
NSLog(#"old date saved : %#",datesaved);
[dateFormatter release];
}
and
find current date .
Now i want to compare current date with the date saved in NSUserDefaults to find number of day in between them.
ex:
The Current Time is 2012-12-16 19:12:74
old date saved : 2012-12-12
19:12:74
Number of days : 4
Thanks
NSDate *date1 = [NSDate dateWithString:#"2010-01-01 00:00:00 +0000"];
NSDate *date2 = [NSDate dateWithString:#"2010-02-03 00:00:00 +0000"];
NSTimeInterval secondsBetween = [date2 timeIntervalSinceDate:date1];
int numberOfDays = secondsBetween / 86400;
NSLog(#"There are %d days in between the two dates.", numberOfDays);
You can take the day component of a date this way:
NSDate* now = [NSDate date]; // Or date from format
NSCalendar* cal = [NSCalendar currentCalendar];
NSDateComponents* components = [cal components: NSDayCalendarUnit fromDate: now];
NSInteger day = [components day];
Do the same for the other date and compare them.
I am trying to get current date with adding device time zone but is show 1 hr late that original date. I thing , I am getting problem of DaylightSavingTime.
How to disable isDaylightSavingTime = FALSE .
here is the code, I have used..
NSDate *date = [NSDate Date];
NSTimeZone *currentTimeZon = [NSTimeZone localTimeZone];
if ([currentTimeZon isDaylightSavingTime])
{
NSLog(#"East coast is NOT on DT");
}
else
{
NSLog(#"East coast is on DT");
}
NSTimeInterval timeZoneOffset = [currentTimeZon secondsFromGMTForDate:currentDate];
NSTimeInterval gmtTimeInterval = [date timeIntervalSinceReferenceDate] - timeZoneOffset;
NSDate *gmtDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];
NSLog(#"### Announcement gmtDate = %#",gmtDate);
I am getting time with 1 Hour difference, date is perfact.
Use NSCalendar, it understands time zones, daylight savings, etc. As #albertamg says, NSDate is just the time since a reference at UTC (GMT), it has no other concept.
I am trying to increment my NSDate. I have an NSDictionary, I am trying to increment my NSDate content in it. Say my NSDate is 2011-07-11, I want to increment the NSDate content in it.
got
{
ConditionDatenew = "2011-07-21 13:31:46 +0000";
Yesterday = "2011-07-20 13:31:46 +0000";
city = #;
condition = "Isolated Thunderstorms";
country = #;
"day_of_week" = Sun;
high = 86;
icon = "chance_of_storm.gif";
low = 68;
state = #;
}
I just want to get the date as 2011-07-22 in my ConditionDatenew in the next dictionary loop. How can I get it?
Create a new date object, and replace the old value in the dictionary. Dates are immutable.
NSDate *newDate = [NSDate date];
[dictionary setObject:newDate forKey:#"ConditionDatenew"];
[NSDate date] will set this to "now."
The easiest way to add a day is to add 24 hours. This works as long as DST is never an issue, and by "increment a day" you mean "increment by 24 hours." If you work exclusively in UTC, then that's fine.
NSDate *newDate = [oldDate dateByAddingTimeInterval:24*60*60];
If DST is an issue (and it usually is), and by "increment a day" you mean "increment by a Gregorian calendar day" then you need to use date components to make sure you add 23, 24 or 25 hours as appropriate.
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setYear:2011];
[dateComponents setMonth:11];
[dateComponents setDay:6];
[dateComponents setTimeZone:[NSTimeZone timeZoneWithName:#"America/New_York"]];
NSDate *date = [calendar dateFromComponents:dateComponents];
NSDateComponents *addComponents = [[NSDateComponents alloc] init];
[addComponents setDay:1];
[addComponents setTimeZone:[NSTimeZone localTimeZone]];
NSDate *newDate = [calendar dateByAddingComponents:addComponents toDate:date options:0];
NSLog(#"oldDate=%#", [date descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"+24=%#", [[date dateByAddingTimeInterval:24*60*60] descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"newDate=%#", [newDate descriptionWithLocale:[NSLocale currentLocale]]);
[calendar release];
[dateComponents release];
[addComponents release];
Output:
oldDate=Sunday, November 6, 2011 12:00:00 AM Eastern Daylight Time
+24=Sunday, November 6, 2011 11:00:00 PM Eastern Standard Time
newDate=Monday, November 7, 2011 12:00:00 AM Eastern Standard Time
If you don't care about the time, and have control over what you set it to, one trick is to set the time to noon. That way adding 24 hours will always fall on the correct day. I don't generally recommend this because it fails badly if you ever forget and create a date with a time of midnight. It's easier to put all of your day-incrementing code in one place and fix the DST problem one time than to make sure all of your date creation code is always right. So I recommend getting used to date components.
Try this:
NSDate *newDate = [NSDate date];
[dictionary setValue:newDate forKey:#"ConditionDatenew"];
Alright I've given up on this. Here's what I'm trying to do: I have a sunrise, sunset, and the current time in a certain timezone. I want to know if it's day or night by figuring out if the current time lies between the sunrise and the sunset times.
Here's what I have:
NSLog(#"%# - %# - %#",currTime,sunrise,sunset);
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];
NSDateFormatter *formatter2 = [[NSDateFormatter alloc]init];
[formatter1 setDateFormat:#"hh:mm a"];
[formatter2 setDateFormat:#"EEE, dd MMM yyyy h:mm a z"];
NSDate *rise = [formatter1 dateFromString:sunrise];
NSDate *set = [formatter1 dateFromString:sunset];
NSDate *time = [formatter2 dateFromString:currTime];
[formatter1 release];
[formatter2 release];
unsigned int flags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components1 = [calendar components:flags fromDate:rise];
NSDateComponents *components2 = [calendar components:flags fromDate:set];
NSDateComponents *components3 = [calendar components:flags fromDate:time];
NSDate *Sunrise = [calendar dateFromComponents:components1];
NSDate *Sunset = [calendar dateFromComponents:components2];
NSDate *Time = [calendar dateFromComponents:components3];
NSLog(#"\nSunrise: %# \nSunset:%# \nTime:%#",rise,set,time);
NSLog(#"\nSunrise: %# \nSunset:%# \nTime:%#",Sunrise,Sunset,Time);
Here's the first output:
Fri, 10 Jun 2011 4:00 am SAST - 7:46 am - 5:41 pm
And here's the second (before making it only concerned about the time, not date)
Sunrise: 1969-12-31 22:46:00 +0000
Sunset: 1970-01-01 08:41:00 +0000
Time: 2011-06-10 02:00:00 +0000
And finally here is the last output (notice how the times are messed up?):
Sunrise: 0001-12-31 22:27:01 +0000
Sunset: 0001-01-01 08:22:01 +0000
Time: 0001-01-01 01:41:01 +0000
So I wanted to pop those resulting dates into my method that checks whether it's in between the dates:
+(BOOL)date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate {
return (([date compare:beginDate] != NSOrderedAscending) && ([date compare:endDate] != NSOrderedDescending));
}
However, until I get the date problem figured out that method won't work. :/ I need help! What am I doing wrong?
Ok, so I gave up on trying to get NSDates to work for me. The timezone issues just killed my brain for the weekend. Anyway, I decided to use BoopMeister suggestion, but it doesn't work quite like I expect. Here's an example:
Using the setup from above, I added these lines:
NSInteger riseHour = [components1 hour];
NSInteger setHour = [components2 hour];
NSInteger timeHour = [components3 hour];
NSLog(#"Rise: %i Set: %i Time: %i",riseHour,setHour,timeHour);
Now, when I plug in these variables:
Current time: Fri, 10 Jun 2011 9:07 am CDT
Sunrise: 6:33 am
Sunset: 8:32 pm
However, when I output the strings from the methods above here's what I get:
Rise: 6 Set: 20 Time: 23
What the?
I would use the components you already have and not make new dates.
Starting at this point in your code:
NSDateComponents *riseComponents = [calendar components:flags fromDate:rise];
NSDateComponents *setComponents = [calendar components:flags fromDate:set];
NSDateComponents *timeComponents = [calendar components:flags fromDate:time];
And then something like
NSInteger riseHour = [riseComponents hour];
NSInteger setHour = [setComponents hour];
NSInteger timeHour = [timeComponents hour];
// Do some checks here
// If necessary do the same for the minutes ([components minute])
Comparing dates has been a performance issue in my app and since you already have the dateComponents it would be faster to make your own check and use the NSIntegers.
Okay, so as can be seen in the question, it gives the numerical presentation of the hours. Same works for the minutes. Build your checks after that.
What probably is the problem with the current time, is the calendar you use. It automatically converts the time to the time in the timezone of the calendar you use. You can also create a calendar with a string representation of the timezone. It's in the API of NSCalendar I think. Then after you made that calendar, then use that one for the current time.
One of the key things about NSDate is that it is in GMT. Always. However when you log it, it prints according to the user's locale.
Now when you do,
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];
[formatter1 setDateFormat:#"hh:mm a"];
NSDate *rise = [formatter1 dateFromString:sunrise];
NSDate *set = [formatter1 dateFromString:sunset];
[formatter1 release];
You are just providing information about hour, minute and whether it is AM/PM. How is it to know which day the time belongs to. It fills this lack of information by defaulting to 01/01/1970 and timezone based on the user's locale. You do provide the timezone information in the current time which might or might not be the same as the user's locale.
To fix this, you must generate a string that includes the date and timezone info for the sunset time and pass it to the date formatter with the correct format to get the date. I am assuming you must've this (or how else will you know that it is the sunset or sunrise time for that day?). Since you know the place you should be able to get the timezone info as well. Once you've the correct information to build the dates with, every comparison method that you've used will work.