mirror of
https://github.com/zhigang1992/SORelativeDateTransformer.git
synced 2026-01-12 17:52:35 +08:00
Bringing in Doug Scandrett's mods for generating more detailed relative date phrases into a branch for posterity.
--HG-- branch : more-detailed-datephrase-generation
This commit is contained in:
@@ -42,7 +42,7 @@
|
||||
F2A33B3C12AD9CA400459019 /* SORelativeDateTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SORelativeDateTransformer.m; path = ../SORelativeDateTransformer/SORelativeDateTransformer.m; sourceTree = "<group>"; };
|
||||
F2A33B3D12AD9CA400459019 /* TesterViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TesterViewController.h; sourceTree = "<group>"; };
|
||||
F2A33B3E12AD9CA400459019 /* TesterViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TesterViewController.m; sourceTree = "<group>"; };
|
||||
F2CD10CF166401CA004A81F3 /* README.markdown */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.markdown; path = ../README.markdown; sourceTree = "<group>"; };
|
||||
F2CD10CF166401CA004A81F3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
||||
F2CD10D1166402F8004A81F3 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAD012DB16C8311E00AF7B51 /* SORelativeDateTransformer.bundle */,
|
||||
F2CD10CF166401CA004A81F3 /* README.markdown */,
|
||||
F2CD10CF166401CA004A81F3 /* README.md */,
|
||||
F2A33B3B12AD9CA400459019 /* SORelativeDateTransformer.h */,
|
||||
F2A33B3C12AD9CA400459019 /* SORelativeDateTransformer.m */,
|
||||
F2A33B3412AD9C7C00459019 /* Tester App Source */,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
}
|
||||
|
||||
- (IBAction) datePickerChangedValue:(id)sender;
|
||||
- (IBAction) relativeDepthChangeValue:(UISegmentedControl *)sender;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -28,4 +28,11 @@
|
||||
[relativeDateLabel setText: [relativeDateTransformer transformedValue:[datePicker date]]];
|
||||
}
|
||||
|
||||
- (IBAction) relativeDepthChangeValue:(UISegmentedControl *)sender
|
||||
{
|
||||
relativeDateTransformer.relativeTransformDepth = (RelativeTransformDepth)sender.selectedSegmentIndex;
|
||||
// update UI
|
||||
[relativeDateLabel setText: [relativeDateTransformer transformedValue:[datePicker date]]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1280</int>
|
||||
<string key="IBDocument.SystemVersion">12C54</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">2843</string>
|
||||
<string key="IBDocument.SystemVersion">12C3006</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">3084</string>
|
||||
<string key="IBDocument.AppKitVersion">1187.34</string>
|
||||
<string key="IBDocument.HIToolboxVersion">625.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">1929</string>
|
||||
<string key="NS.object.0">2083</string>
|
||||
</object>
|
||||
<array key="IBDocument.IntegratedClassDependencies">
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUIDatePicker</string>
|
||||
<string>IBUILabel</string>
|
||||
<string>IBUISegmentedControl</string>
|
||||
<string>IBUIView</string>
|
||||
</array>
|
||||
<array key="IBDocument.PluginDependencies">
|
||||
@@ -82,6 +83,7 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
<string key="NSFrame">{{20, 334}, {280, 61}}</string>
|
||||
<reference key="NSSuperview" ref="774585933"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="1035436030"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA</bytes>
|
||||
@@ -160,6 +162,44 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
|
||||
<double key="preferredMaxLayoutWidth">275</double>
|
||||
</object>
|
||||
<object class="IBUISegmentedControl" id="1035436030">
|
||||
<reference key="NSNextResponder" ref="774585933"/>
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{16, 410}, {290, 30}}</string>
|
||||
<reference key="NSSuperview" ref="774585933"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<int key="IBSegmentControlStyle">2</int>
|
||||
<int key="IBNumberOfSegments">3</int>
|
||||
<int key="IBSelectedSegmentIndex">0</int>
|
||||
<array key="IBSegmentTitles">
|
||||
<string>First Match</string>
|
||||
<string>Second Match</string>
|
||||
<string>Third Match</string>
|
||||
</array>
|
||||
<array class="NSMutableArray" key="IBSegmentWidths">
|
||||
<real value="0.0"/>
|
||||
<real value="0.0"/>
|
||||
<real value="0.0"/>
|
||||
</array>
|
||||
<array class="NSMutableArray" key="IBSegmentEnabledStates">
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
<boolean value="YES"/>
|
||||
</array>
|
||||
<array class="NSMutableArray" key="IBSegmentContentOffsets">
|
||||
<string>{0, 0}</string>
|
||||
<string>{0, 0}</string>
|
||||
<string>{0, 0}</string>
|
||||
</array>
|
||||
<array class="NSMutableArray" key="IBSegmentImages">
|
||||
<object class="NSNull" id="4"/>
|
||||
<reference ref="4"/>
|
||||
<reference ref="4"/>
|
||||
</array>
|
||||
</object>
|
||||
</array>
|
||||
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
@@ -209,6 +249,15 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
</object>
|
||||
<int key="connectionID">14</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">relativeDepthChangeValue:</string>
|
||||
<reference key="source" ref="1035436030"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">13</int>
|
||||
</object>
|
||||
<int key="connectionID">16</int>
|
||||
</object>
|
||||
</array>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<array key="orderedObjects">
|
||||
@@ -236,6 +285,7 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
<reference ref="7301982"/>
|
||||
<reference ref="210052879"/>
|
||||
<reference ref="1007823394"/>
|
||||
<reference ref="1035436030"/>
|
||||
</array>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
@@ -254,6 +304,11 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
<reference key="object" ref="7301982"/>
|
||||
<reference key="parent" ref="774585933"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">15</int>
|
||||
<reference key="object" ref="1035436030"/>
|
||||
<reference key="parent" ref="774585933"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||
@@ -263,6 +318,7 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="10.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="11.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="15.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="6.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="9.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</dictionary>
|
||||
@@ -270,24 +326,27 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
<nil key="activeLocalization"/>
|
||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">14</int>
|
||||
<int key="maxID">16</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">TesterViewController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">datePickerChangedValue:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">datePickerChangedValue:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<dictionary class="NSMutableDictionary" key="actions">
|
||||
<string key="datePickerChangedValue:">id</string>
|
||||
<string key="relativeDepthChangeValue:">UISegmentedControl</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="actionInfosByName">
|
||||
<object class="IBActionInfo" key="datePickerChangedValue:">
|
||||
<string key="name">datePickerChangedValue:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBActionInfo" key="relativeDepthChangeValue:">
|
||||
<string key="name">relativeDepthChangeValue:</string>
|
||||
<string key="candidateClassName">UISegmentedControl</string>
|
||||
</object>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="outlets">
|
||||
<string key="datePicker">UIDatePicker</string>
|
||||
<string key="relativeDateLabel">UILabel</string>
|
||||
@@ -317,10 +376,10 @@ AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA</b
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
|
||||
<real value="1536" key="NS.object.0"/>
|
||||
<real value="1552" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">1929</string>
|
||||
<string key="IBCocoaTouchPluginVersion">2083</string>
|
||||
</data>
|
||||
</archive>
|
||||
|
||||
Binary file not shown.
@@ -28,12 +28,20 @@ SORelativeDateTransformer is a value transformer that generates a human-readable
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum {
|
||||
FirstMatchOnly = 0,
|
||||
IncludeSecondMatchIgnoreZero,
|
||||
IncludeThirdMatchIgnoreZero,
|
||||
}RelativeTransformDepth;
|
||||
|
||||
@interface SORelativeDateTransformer : NSValueTransformer
|
||||
{
|
||||
NSCalendar *__calendar;
|
||||
NSUInteger __unitFlags;
|
||||
NSArray *__dateComponentSelectorNames;
|
||||
NSMutableArray *__partialDateStrings;
|
||||
}
|
||||
@property (nonatomic) RelativeTransformDepth relativeTransformDepth;
|
||||
|
||||
/**
|
||||
\brief Transform an NSDate into a phrase expressing the relative difference between that date and now.
|
||||
|
||||
@@ -43,6 +43,9 @@ static inline NSString *SORelativeDateLocalizedString(NSString *key, NSString *c
|
||||
__unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
|
||||
__dateComponentSelectorNames = [[NSArray alloc] initWithObjects:@"year", @"month", @"week", @"day", @"hour", @"minute", @"second", nil];
|
||||
|
||||
__partialDateStrings = [[NSMutableArray alloc] init];
|
||||
_relativeTransformDepth = FirstMatchOnly;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -51,6 +54,7 @@ static inline NSString *SORelativeDateLocalizedString(NSString *key, NSString *c
|
||||
{
|
||||
[__calendar release];
|
||||
[__dateComponentSelectorNames release];
|
||||
[__partialDateStrings release];
|
||||
[super dealloc];
|
||||
}
|
||||
#endif
|
||||
@@ -76,6 +80,9 @@ static inline NSString *SORelativeDateLocalizedString(NSString *key, NSString *c
|
||||
return SORelativeDateLocalizedString(@"now", @"label for current date-time");
|
||||
}
|
||||
|
||||
// Clear any stored values
|
||||
[__partialDateStrings removeAllObjects];
|
||||
|
||||
// Default return value is "now".
|
||||
|
||||
id transformedValue = SORelativeDateLocalizedString(@"now", @"label for current date-time");
|
||||
@@ -87,7 +94,10 @@ static inline NSString *SORelativeDateLocalizedString(NSString *key, NSString *c
|
||||
// Iterate the array of NSDateComponent selectors, which are sorted in decreasing order of time span: year, month, day, etc.
|
||||
// For the first NSDateComponent time span method that returns a reasonable non-zero value, use that value to compute the relative-to-now date phrase string.
|
||||
|
||||
|
||||
// Keep track of relative transform depth, compare against desired.
|
||||
RelativeTransformDepth currentDepth = FirstMatchOnly;
|
||||
BOOL isRelativePastDate;
|
||||
|
||||
for (NSString *selectorName in __dateComponentSelectorNames)
|
||||
{
|
||||
// Invoke the NSDateComponent selector matching the current iteration, and obtain the component's value.
|
||||
@@ -123,28 +133,63 @@ static inline NSString *SORelativeDateLocalizedString(NSString *key, NSString *c
|
||||
|
||||
// Generate the langugage-friendly phrase representing the relative difference between the input date and now.
|
||||
|
||||
BOOL isRelativePastDate = (relativeDifference > 0); // positive values indicate a relative past date; negative values indicate a future date.
|
||||
|
||||
// Use the appropriate string formatting template depending on whether the given date is a relative past or a relative future date.
|
||||
isRelativePastDate = (relativeDifference > 0); // positive values indicate a relative past date; negative values indicate a future date.
|
||||
|
||||
if (isRelativePastDate) {
|
||||
// Fetch the string format template for relative past dates from the localization file and crunch out a formatted string.
|
||||
NSString *pastDatePhraseTemplate = SORelativeDateLocalizedString(@"formatTemplateForRelativePastDatePhrase", nil);
|
||||
transformedValue = [NSString stringWithFormat:pastDatePhraseTemplate, relativeDifference, localizedDateComponentName];
|
||||
} else {
|
||||
// Fetch the string format template for relative future dates from the localization file and crunch out a formatted string.
|
||||
NSString *futureDatePhraseTemplate = SORelativeDateLocalizedString(@"formatTemplateForRelativeFutureDatePhrase", nil);
|
||||
transformedValue = [NSString stringWithFormat:futureDatePhraseTemplate, labs (relativeDifference), localizedDateComponentName];
|
||||
}
|
||||
|
||||
// Break from the date components iteration loop after finding the first one with a non-zero relative difference value.
|
||||
break;
|
||||
|
||||
// if current depth is not further than expected, collect value pair
|
||||
if (self.relativeTransformDepth >= currentDepth) {
|
||||
// collect the target phrase for later use
|
||||
NSString *template = SORelativeDateLocalizedString(@"formatTemplateSingleValuePair", nil);
|
||||
NSString *existing = [NSString stringWithFormat:template, labs (relativeDifference), localizedDateComponentName];
|
||||
[__partialDateStrings addObject:existing];
|
||||
currentDepth++;
|
||||
}
|
||||
} // for loop
|
||||
|
||||
|
||||
NSUInteger available = [__partialDateStrings count];
|
||||
if (available > 0) {
|
||||
transformedValue = [self transformForDepth:available-1
|
||||
isPast:isRelativePastDate];
|
||||
}
|
||||
|
||||
return transformedValue;
|
||||
}
|
||||
|
||||
- (NSString *)transformForDepth:(RelativeTransformDepth)currentDepth
|
||||
isPast:(BOOL)isRelativePastDate {
|
||||
|
||||
// Use the appropriate string formatting template depending on whether the given date is a relative past or a relative future date.
|
||||
NSMutableString *transformedValue = [NSMutableString string];
|
||||
NSString *templateForDepth;
|
||||
if (isRelativePastDate) {
|
||||
// Fetch the string format template for relative past dates from the localization file and crunch out a formatted string.
|
||||
templateForDepth = [NSString stringWithFormat:@"formatTemplateForRelativePastDatePhrase_Depth%i",currentDepth];
|
||||
} else {
|
||||
// Fetch the string format template for relative future dates from the localization file and crunch out a formatted string.
|
||||
templateForDepth = [NSString stringWithFormat:@"formatTemplateForRelativeFutureDatePhrase_Depth%i",currentDepth];
|
||||
}
|
||||
NSString *datePhraseTemplate = SORelativeDateLocalizedString(templateForDepth, nil);
|
||||
NSScanner *scanner = [NSScanner scannerWithString:datePhraseTemplate];
|
||||
scanner.charactersToBeSkipped = nil;
|
||||
NSString *target = nil;
|
||||
|
||||
// Scan up to the %@, append the partial, move the scanner, repeat
|
||||
for (NSString *partialString in __partialDateStrings) {
|
||||
[scanner scanUpToString:@"%@" intoString:&target];
|
||||
if (!target) { // check to protect against %@ at the beginning of template
|
||||
target = @"";
|
||||
}
|
||||
target = [target stringByAppendingString:partialString];
|
||||
[scanner setScanLocation:scanner.scanLocation+2];
|
||||
[transformedValue appendString:target];
|
||||
}
|
||||
if (!scanner.isAtEnd) {
|
||||
[scanner scanUpToString:@"________fin__" intoString:&target];
|
||||
if (target) {
|
||||
[transformedValue appendString:target];
|
||||
}
|
||||
}
|
||||
return transformedValue;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user