Implement -components:fromDate:toDate:options:

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@39202 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
thebeing 2015-11-30 10:06:04 +00:00
parent cf85f75b01
commit 27de2178a1
4 changed files with 144 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2015-11-30: Niels Grewe <niels.grewe@halbordnung.de>
* Source/NSCalendar.h
* Headers/Foundation/NSCalendar.h:
Implement -components:fromDate:toDate:options:. (Not handling
NSWrapCalendarComponents yet.)
* Tests/base/NSCalendar/component-diff.m:
Test case for new functionality.
2015-11-22 Riccardo Mottola <rm@gnu.org>
* Source/NSFileManager.m (createDirectoryAtPath)

View file

@ -194,6 +194,17 @@ enum
- (NSDateComponents *) components: (NSUInteger) unitFlags
fromDate: (NSDate *) date;
/**
* Compute the different between the specified components in the two dates.
* Values are summed up as long as now higher-granularity unit is specified.
* That means if you want to extract the year and the day from two dates
* which are 13 months + 1 day apart, you will get 1 as the result for the year
* but the rest of the difference in days. (29 <= x <= 32, depending on the
* month).
*
* Please note that the NSWrapCalendarComponents option that should affect the
* calculations is not presently supported.
*/
- (NSDateComponents *) components: (NSUInteger) unitFlags
fromDate: (NSDate *) startingDate
toDate: (NSDate *) resultDate

View file

@ -367,12 +367,81 @@ static NSRecursiveLock *classLock = nil;
#endif
}
/*
* Convenience macro for field extraction.
* TODO: We need to implement NSWrapCalendarComponents, but it is unclear how that
* actually works.
*/
#define COMPONENT_DIFF(cal, units, components, toDate, nsunit, setSel, uunit, err) \
do { if (units & nsunit) \
{ \
int32_t uunit ## Diff = ucal_getFieldDifference(cal, toDate, uunit, &err); \
if (U_FAILURE(err)) \
{ \
RELEASE(components); \
return nil; \
} \
[components setSel uunit ## Diff]; \
} \
} while (0)
- (NSDateComponents *) components: (NSUInteger) unitFlags
fromDate: (NSDate *) startingDate
toDate: (NSDate *) resultDate
options: (NSUInteger) opts
{
#if GS_USE_ICU == 1
NSDateComponents *comps = nil;
UErrorCode err = U_ZERO_ERROR;
UDate udateFrom = (UDate)floor([startingDate timeIntervalSince1970] * 1000.0);
UDate udateTo = (UDate)floor([resultDate timeIntervalSince1970] * 1000.0);
ucal_setMillis (my->cal, udateFrom, &err);
if (U_FAILURE(err))
{
return nil;
}
comps = [[NSDateComponents alloc] init];
/*
* Since the ICU field difference function automatically advances the calendar as appropriate, we
* need to process the units from the largest to the smallest.
*/
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSEraCalendarUnit, setEra:, UCAL_ERA, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSYearCalendarUnit, setYear:, UCAL_YEAR, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSMonthCalendarUnit, setMonth:, UCAL_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSWeekOfYearCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
if (!(unitFlags & NSWeekOfYearCalendarUnit))
{
/* We must avoid setting the same unit twice (it would be zero because
* of the automatic advancement.
*/
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSWeekCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
}
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSWeekOfMonthCalendarUnit, setWeekOfMonth:, UCAL_WEEK_OF_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSDayCalendarUnit, setDay:, UCAL_DAY_OF_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSWeekdayOrdinalCalendarUnit, setWeekdayOrdinal:, UCAL_DAY_OF_WEEK_IN_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSWeekdayCalendarUnit, setWeekday:, UCAL_DAY_OF_WEEK, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSHourCalendarUnit, setHour:, UCAL_HOUR_OF_DAY, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSMinuteCalendarUnit, setMinute:, UCAL_MINUTE, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo, NSSecondCalendarUnit, setSecond:, UCAL_SECOND, err);
# if 0
if (unitFlags & NSCalendarUnitNanosecond)
{
int32_t ns = ucal_getFieldDifference(my->cal, udateTo, UCAL_MILLISECOND, &err) * 1000000;
if (U_FAILURE(err))
{
RELEASE(comps);
return nil;
}
[comps setNanosecond: ns];
}
# endif
return AUTORELEASE(comps);
#else
return nil;
#endif
}
- (NSDate *) dateByAddingComponents: (NSDateComponents *) comps

View file

@ -0,0 +1,55 @@
#import "Testing.h"
#import "ObjectTesting.h"
#import <Foundation/NSCalendar.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSLocale.h>
#include <stdio.h>
#if defined(GS_USE_ICU)
#define NSCALENDAR_SUPPORTED GS_USE_ICU
#else
#define NSCALENDAR_SUPPORTED 1 /* Assume Apple support */
#endif
int main()
{
NSDateComponents *comps;
NSCalendar *cal;
NSDate *date;
NSDate *date2;
START_SET("NSCalendar date component differences")
if (!NSCALENDAR_SUPPORTED)
SKIP("NSCalendar not supported\nThe ICU library was not available when GNUstep-base was built")
cal = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
[cal setFirstWeekday: 1];
date = [NSDate dateWithString: @"2015-01-01 01:01:01 +0100"];
date2 = [NSDate dateWithString: @"2015-02-03 04:05:06 +0100"];
comps = [cal components: NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
| NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit
fromDate: date
toDate: date2
options: 0];
PASS([comps year] == 0, "year difference correct");
PASS([comps month] == 1, "month difference correct");
PASS([comps day] == 2, "day difference correct");
PASS([comps hour] == 3, "hour difference correct");
PASS([comps minute] == 4, "minute difference correct");
PASS([comps second] == 5, "second difference correct");
comps = [cal components: NSDayCalendarUnit
fromDate: date
toDate: date2
options: 0];
PASS([comps month] == NSNotFound, "no month returned if not requested");
PASS([comps day] == 33, "day difference without larger unit correct");
RELEASE(cal);
END_SET("NSCalendar date component differences")
return 0;
}