I have an issue: setFirstWeekDay doesn't work... I don't know why ...
NSCalendar *gregorianT = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorianT setFirstWeekday:2];
NSDateFormatter *formatDayWeek = [[NSDateFormatter alloc] init];
[formatDayWeek setDateFormat:#"c EEEE"];
NSLog(#"date : %# value for date : %#", dateForMonth, [formatDayWeek stringFromDate:dateForMonth]);
This is what I got:
date : 2012-11-23 14:18:28 +0000 value for date : 6 Friday
And I should get date : 2012-11-23 14:18:28 +0000 value for date : 5 Friday
The issue is that you are really dealing with three separate objects here: an NSCalendar, an NSDate, and an NSDateFormatter (which is not using the NSCalendar object you created). The three aren't implicitly connected; when you pass in the NSDate to the date formatter, you're completely pulling your custom NSCalendar, with the modified weekday, out of the equation. Remember: an NSDate object is simply a measure of time from a reference point (such as number of seconds from 1/1/2001 Midnight GMT)... it's the calendar object that has the concept of "day name," day ordinality," etc for that measure of time.
If you want to see the modified ordinality, pass in your calendar object to the formatter:
NSCalendar *gregorianT = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorianT setFirstWeekday:2];
NSDateFormatter *formatDayWeek = [[NSDateFormatter alloc] init];
[formatDayWeek setCalendar:gregorianT];
[formatDayWeek setDateFormat:#"c EEEE"];
NSLog(#"Value for date: %#", [formatDayWeek stringFromDate:dateForMonth]);
...or you can access the ordinality directly from your NSCalendar object.
NSCalendar *gregorianT = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorianT setFirstWeekday:2];
NSUInteger valueOfDay = [gregorianT ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:dateForMonth];
NSLog(#"Value for date : %ld", (long)valueOfDay);
Related
This question already has an answer here:
returns a date an hour in the future
(1 answer)
Closed 7 years ago.
This is my code.
NSString *dateString = #"2015-06-03 02:19:37";
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
NSLog(#"converted date = %#",[formatter dateFromString:dateString]);
The output of the code above is: "converted date = 2015-06-02 18:19:37 +0000". I know that this is because it converts the NSString with respect to GMT, but what i wanted to happen is NSDate must be 2015-06-03 02:19:37, same with dateString
I know that this is because [the NSDateFormatter] converts the NSString with respect to GMT…
No, you're wrong. NSDateFormatter defaults to using your current time zone.
What you're not understanding is that "2015-06-02 18:19:37 +0000" is the same date and time as "2015-06-03 02:19:37" (in your local time zone, which must be GMT+0800).
Also, the description that you logged is just one representation of the date. The date does not have a year, month, day-of-month, hour, minute, second, or any of that. A date object just represents a moment in time. Such moments don't have any of that and neither do NSDate objects. Only representations of moments have those things, and they are only arrived at by processing the date through a specific calendar and time zone. In any case, any given date has multiple representations. Just because the description that gets logged happens to choose a representation that you weren't expecting doesn't mean the date is wrong.
You have implicitly requested a conversion from an NSDate object to a string when you logged it. That's because logging always involves strings. The string-formatting code used by NSLog() and the %# format specifier uses the -description method. You are never going to be able to force NSDate's implementation of -description to use your time zone, so don't try.
If you really need a string representation (and you're not just debugging) and you want it in some specific time zone or otherwise want to dictate the format, don't rely on the -description method like you are. Instead, use a date formatter to convert from NSDate to an NSString explicitly, and configure the date formatter to produce the representation that you want.
But don't confuse the need to do that with the date being wrong.
What I really wanted to do is to check if the given NSDate is already past 9PM EST (-4GMT), while i'm on +8GMT timezone.
So, use NSCalendar, NSTimeZone, and NSDateComponents to construct an NSDate for 9PM EST (on the current day, I suppose you mean) and then compare the dates.
NSDate* date = /* ... */;
NSCalendar* calendar = [[NSCalendar alloc] initWithIdentifier:NSCalendarIdentifierGregorian];
calendar.timeZone = [NSTimeZone timeZoneWithName:#"America/New_York"];
NSDate* deadline = [calendar dateBySettingHour:21 minute:0 second:0 ofDate:date options:0];
if ([date compare:deadline] == NSOrderedDescending)
/* date is after deadline */;
Here I used the convenience method -dateBySettingHour:minute:second:ofDate:options: and avoided direct use of NSDateComponents. If your needs differ, you might have to convert the date to date components using the calender, modify the components, convert them back to a date, and then compare.
Use the NSDateComponents class to build the date from the information in the string. The documentation explicitly provides an example of this:
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:6];
[comps setMonth:5];
[comps setYear:2004];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];
[comps release];
NSDateComponents *weekdayComponents =
[gregorian components:NSWeekdayCalendarUnit fromDate:date];
int weekday = [weekdayComponents weekday];
call this method with your string value...
- (NSDate *)dateFromString:(NSString *)date
{
static NSDateFormatter *dateFormatter;
if (!dateFormatter)
{
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
}
NSLog(#"Date: %#",date);
return [dateFormatter dateFromString:date];
}
RESULT : Date: 2015-06-03 02:19:37
NSString *dateString = #"2015-06-03 02:19:37";
NSDateFormatter *f = [[NSDateFormatter alloc] init];
[f setDateFormat:#"yyyy-MM-dd"];
NSDate *startDate = [f dateFromString:dateString];
You will get the NSDate here(startDate).... May this help to you.....
If I'm not interested in the time can I ignore it? I.e I have a date string that looks like this #"2012-12-19T14:00:00" but I'm only interested in getting the date (2012-12-19) but if I set NSDateFormatter like [dateFormatter setDateFormat:#"yyyy-MM-dd"]; it will return me a nil NSDate.
An NSDate object will always contain a time component as well, as it is representing a point in time — from this perspective one could argue the name NSDate is misleading.
You should create a date formatter for creating dates from string, set the time to the start of the day and use a second date formatter to output the date without time component.
NSString *dateString = #"2012-12-19T14:00:00";
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
[outputFormatter setDateStyle:NSDateFormatterShortStyle];
[outputFormatter setTimeStyle:NSDateFormatterNoStyle];
NSDate *date = [inputFormatter dateFromString:dateString];
//this will set date's time components to 00:00
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit
startDate:&date
interval:NULL
forDate:date];
NSString *outputString = [outputFormatter stringFromDate:date];
NSLog(#"%#", outputString);
results in
19.12.12
while the format — as it is chosen by styling — will be dependent of your environment locale
all date string returns 10 characters for the date, what i mean is the date of todayy will be 2012-11-19
you can easily substring the date and use it as you want:
Example :
NSString* newDate = #"";
newDate = [[NSDate date]substringToIndex:10];
the out put will be : 2012-11-19
I found the codes to calculate days difference between two dates here.
I write a method :
-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:startDate];
NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:endDate];
return endDay-startDay;
}
This method has a problem: it can't consider the timezone thing. Even I add a line like this:
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
My test code is like this:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSString *strDate = #"2012-09-03 23:00:00";
NSDate *dateStart = [dateFormat dateFromString:strDate];
strDate = #"2012-09-04 01:00:00";
NSDate *dateEnd = [dateFormat dateFromString:strDate];
NSLog(#"Days difference between %# and %# is: %d days",[dateFormat stringFromDate:dateStart],[dateFormat stringFromDate:dateEnd],[self daysWithinEraFromDate:dateStart toDate:dateEnd]);
The result is:
Days difference between 2012-09-03 23:00:00 and 2012-09-04 01:00:00 is: 0 days
I want to get 1 day as result by the number of midnights between the two dates. My timezone is GMT +8. But this calculation is based on GMT, so I get the wrong days number. Is there anyway to solve this problem? Thank you.
Scott Lemmon's method can solve my problem. I rewrite my code like this:
-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
NSDate *newDate1 = [startDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSDate *newDate2 = [endDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate1];
NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate2];
return endDay-startDay;
}
If the time zone offset isn't working, how about just add or subtract it manually instead?
In your case NSDate *newDate = [oldDate dateByAddingTimeInterval:(-8 * 60 * 60)]; to subtract off your +8 hours.
Or if you want to find the GMT offset automatically as well then it would simply be NSDate *newDate = [oldDate dateByAddingTimeInterval:(-[[NSTimeZone localTimeZone] secondsFromGMT])
Another thought:
A perhaps easier solution would be to just disregard the time information altogether. Just set it to the same arbitrary number for both dates, then as long as the dates come from the same timezone you will always get the correct number of mid-nights between them, regardless of GMT offset.
What you really want is the NSDate method timeIntervalSinceDate:, and take that result and if it's more than 0 but less than 86400 (the number of seconds in a day), that's one day. Otherwise, divide your result by 86400 and you'll get the number of days.
The way you currently have your code, there's only 2 hours between the two days and that's why you are seeing a result of 0 and not one.
Edit - and to determine if midnight has happened, let's try this function I just wrote off the top of my head:
- (NSDate *) getMidnightDateFromDate: (NSDate *) originalDate
{
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSIntegerMax fromDate:originalDate];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
return(midnight);
}
- (BOOL) howManyDaysDifferenceBetween: startDate and: endDate
{
NSDate * firstMidnight = [self getMidnightDateFromDate: startDate];
NSDate * secondMidnight = [self getMidnightDateFromDate: endDate];
NSTimeInterval timeBetween = [firstMidnight timeIntervalSinceDate: secondMidnight];
NSInteger numberOfDays = (timeBetween / 86400);
return(numberOfDays);
}
which I'm basing off Dave Delong's answer to this question. No guarantees that my code will work (I didn't test it), but I think the concept is sound.
I would like to work out the difference in months
at the moment I have this code:
dateInterval = [endDate timeIntervalSinceDate:startDate];
But that returns a value in seconds, I would like to see the difference between the dates in months.
How would I do this?
Thanks
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setDateFormat:#"dd/MM/yyyy"];
NSDate *startDate = [inputFormatter dateFromString:#"07/03/2011"];
NSDate *endDate = [inputFormatter dateFromString:#"07/06/2011"];
NSInteger month_delta = [[[NSCalendar currentCalendar] components: NSMonthCalendarUnit fromDate: startDate toDate: endDate options: 0] month];
NSLog(#"---------------------------->>%d", month_delta);
[inputFormatter release]; // <-- in case not using ARC
it will log:
---------------------------->>3
You can create a NSDateComponents from the NSDates in question and just subtract the total months. (Total months = 12*year+currentMonth)
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/Reference/Reference.html#//apple_ref/occ/cl/NSDateComponents
I'm not sure what's going on with this. I'm trying to load an NSString* object from a file, convert it to an NSDate* with a date formatter, and then convert the hour and minute components back to NSString so I can display a time in Interface Builder. However, instead of the time that was saved to the file, instead I end up with 19 for the hour, and 0 for the minute. (Regardless of what was put in, the program loads four different NSDates)
Here's the code for loading the date from the file (I checked with breakpoints, and the array does indeed have the correct data, so that's not the problem)
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd hh:mm:ss a"];
date1 = [[df dateFromString:[loadArray objectAtIndex:3]] retain];
Here's the code for displaying the date.
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comp = [[gregorian components:NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:myDrug.date1] retain];
hourField1.text = [NSString stringWithFormat:#"%d", comp.hour];
minuteField1.text = [NSString stringWithFormat:#"%d", comp.minute];
(hourField1 and minuteField1 are the IBOutlets that receive the values, by the way)
I'm not sure where I've gone wrong here, and any help would be greatly appreciated. Thanks!
Update:
On the suggestion of some of the people here, I've NSLogged the problem, and I've found that it the date formatter that's not working. An example date is 2011-02-14 06:00:00 GMT, and the date formatter is yyyy-MM-dd hh:mm:ss a, so I'm not sure why it won't work.
If the date strings in loadArray are of the form 2011-02-14 06:00:00 GMT, then the format should be set as follows:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss zzz"]; <--
date1 = [[df dateFromString:[loadArray objectAtIndex:3]] retain];
// the retain above is suspicious btw (but that's another question)
[df release]; //don't forget this
I also changed the hh to HH assuming that the hours are actually in 24-hour instead of 12-hour format. See Unicode Date Format Patterns for details.
Next, when displaying the date, if you want to show the hours and minutes in GMT instead of whatever the user's current time zone is, you'll need to set the calendar's time zone:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSTimeZone *tz = [NSTimeZone timeZoneWithName:#"GMT"]; <--
[gregorian setTimeZone:tz]; <--
NSDateComponents *comp = [gregorian components:NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:myDrug.date1];
//do not do a retain on comp above
hourField1.text = [NSString stringWithFormat:#"%d", comp.hour];
minuteField1.text = [NSString stringWithFormat:#"%d", comp.minute];
[gregorian release]; //don't forget this