Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions DistanceOfTimeInWords.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
C701F2681359B29600468818 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C701F26A1359B29600468818 /* Localizable.strings */; };
5AD7DE05159E2D2C002BD260 /* DistanceOfTimeInWordsLocalizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C701F26A1359B29600468818 /* DistanceOfTimeInWordsLocalizable.strings */; };
C701F2681359B29600468818 /* DistanceOfTimeInWordsLocalizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C701F26A1359B29600468818 /* DistanceOfTimeInWordsLocalizable.strings */; };
C7A88B62135460F2006F686D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A88B61135460F2006F686D /* UIKit.framework */; };
C7A88B64135460F2006F686D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A88B63135460F2006F686D /* Foundation.framework */; };
C7A88B66135460F2006F686D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A88B65135460F2006F686D /* CoreGraphics.framework */; };
Expand Down Expand Up @@ -37,9 +38,10 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
69EAD0211589E57700975F75 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
C701F2691359B29600468818 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
C701F26B1359B2AA00468818 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
5AD7DE04159E2D2C002BD260 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/DistanceOfTimeInWordsLocalizable.strings; sourceTree = "<group>"; };
69EAD0211589E57700975F75 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/DistanceOfTimeInWordsLocalizable.strings"; sourceTree = "<group>"; };
C701F2691359B29600468818 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/DistanceOfTimeInWordsLocalizable.strings; sourceTree = "<group>"; };
C701F26B1359B2AA00468818 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/DistanceOfTimeInWordsLocalizable.strings; sourceTree = "<group>"; };
C7A88B5D135460F2006F686D /* DistanceOfTimeInWords.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DistanceOfTimeInWords.app; sourceTree = BUILT_PRODUCTS_DIR; };
C7A88B61135460F2006F686D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
C7A88B63135460F2006F686D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -140,7 +142,7 @@
C7A88B6A135460F2006F686D /* InfoPlist.strings */,
C7A88B6D135460F2006F686D /* DistanceOfTimeInWords-Prefix.pch */,
C7A88B6E135460F2006F686D /* main.m */,
C701F26A1359B29600468818 /* Localizable.strings */,
C701F26A1359B29600468818 /* DistanceOfTimeInWordsLocalizable.strings */,
);
name = "Supporting Files";
sourceTree = "<group>";
Expand Down Expand Up @@ -210,7 +212,6 @@
C7A88B54135460F2006F686D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0430;
ORGANIZATIONNAME = Grailbox;
};
buildConfigurationList = C7A88B57135460F2006F686D /* Build configuration list for PBXProject "DistanceOfTimeInWords" */;
Expand All @@ -221,6 +222,7 @@
en,
es,
"zh-Hans",
pt,
);
mainGroup = C7A88B52135460F2006F686D;
productRefGroup = C7A88B5E135460F2006F686D /* Products */;
Expand All @@ -241,7 +243,8 @@
C7A88B6C135460F2006F686D /* InfoPlist.strings in Resources */,
C7A88B75135460F2006F686D /* MainWindow.xib in Resources */,
C7A88B7B135460F2006F686D /* DistanceOfTimeInWordsViewController.xib in Resources */,
C701F2681359B29600468818 /* Localizable.strings in Resources */,
C701F2681359B29600468818 /* DistanceOfTimeInWordsLocalizable.strings in Resources */,
5AD7DE05159E2D2C002BD260 /* DistanceOfTimeInWordsLocalizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -303,14 +306,15 @@
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
C701F26A1359B29600468818 /* Localizable.strings */ = {
C701F26A1359B29600468818 /* DistanceOfTimeInWordsLocalizable.strings */ = {
isa = PBXVariantGroup;
children = (
C701F2691359B29600468818 /* en */,
C701F26B1359B2AA00468818 /* es */,
69EAD0211589E57700975F75 /* zh-Hans */,
5AD7DE04159E2D2C002BD260 /* pt */,
);
name = Localizable.strings;
name = DistanceOfTimeInWordsLocalizable.strings;
sourceTree = "<group>";
};
C7A88B6A135460F2006F686D /* InfoPlist.strings */ = {
Expand Down Expand Up @@ -388,7 +392,6 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DistanceOfTimeInWords/DistanceOfTimeInWords-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INFOPLIST_FILE = "DistanceOfTimeInWords/DistanceOfTimeInWords-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
Expand All @@ -402,7 +405,6 @@
COPY_PHASE_STRIP = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DistanceOfTimeInWords/DistanceOfTimeInWords-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INFOPLIST_FILE = "DistanceOfTimeInWords/DistanceOfTimeInWords-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
VALIDATE_PRODUCT = YES;
Expand All @@ -421,7 +423,6 @@
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DistanceOfTimeInWordsTests/DistanceOfTimeInWordsTests-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INFOPLIST_FILE = "DistanceOfTimeInWordsTests/DistanceOfTimeInWordsTests-Info.plist";
OTHER_LDFLAGS = (
"-framework",
Expand All @@ -444,7 +445,6 @@
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DistanceOfTimeInWordsTests/DistanceOfTimeInWordsTests-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INFOPLIST_FILE = "DistanceOfTimeInWordsTests/DistanceOfTimeInWordsTests-Info.plist";
OTHER_LDFLAGS = (
"-framework",
Expand Down
12 changes: 12 additions & 0 deletions DistanceOfTimeInWords/NSDate+Formatting.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@

#import <Foundation/Foundation.h>

//
// Distance of time in words to string components.
typedef enum DistanceOfTimeInWordsStringComponents {
kDOTIWStringComponentModifier = 1, // 00001 in binary.
kDOTIWStringComponentNumber = 2, // 00010 in binary.
kDOTIWStringComponentMeasure = 4, // 00100 in binary.
kDOTIWStringComponentDirection = 8, // 01000 in binary.
kDOTIWStringComponentJustNow = 16, // 10000 in binary (Disabled by default.)
} DistanceOfTimeInWordsStringComponents;

@interface NSDate (formatting)

Expand All @@ -28,4 +37,7 @@
- (NSString *)distanceOfTimeInWords;
- (NSString *)distanceOfTimeInWords:(NSDate *)date;

- (NSString *)distanceOfTimeInWordsWithOptions:(NSUInteger)options;
- (NSString *)distanceOfTimeInWords:(NSDate *)date withOptions:(NSUInteger)options;

@end
83 changes: 59 additions & 24 deletions DistanceOfTimeInWords/NSDate+Formatting.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@

#import "NSDate+Formatting.h"

#define SECONDS_PER_MINUTE 60.0
#define SECONDS_PER_HOUR 3600.0
#define SECONDS_PER_DAY 86400.0
#define SECONDS_PER_MONTH 2592000.0
#define SECONDS_PER_YEAR 31536000.0
#define SECONDS_JUST_NOW_LIMIT 5.0
#define SECONDS_PER_MINUTE 60.0
#define SECONDS_PER_HOUR 3600.0
#define SECONDS_PER_DAY 86400.0
#define SECONDS_PER_MONTH 2592000.0
#define SECONDS_PER_YEAR 31536000.0

#define LOCALIZED_STRING_TABLE_NAME @"DistanceOfTimeInWordsLocalizable"

@implementation NSDate (formatting)

Expand All @@ -50,24 +53,44 @@ - (NSString *)distanceOfTimeInWords {
}

- (NSString *)distanceOfTimeInWords:(NSDate *)date {
NSString *Ago = NSLocalizedString(@"ago", @"Denotes past dates");
NSString *FromNow = NSLocalizedString(@"from now", @"Denotes future dates");
NSString *LessThan = NSLocalizedString(@"Less than", @"Indicates a less-than number");
NSString *About = NSLocalizedString(@"About", @"Indicates an approximate number");
NSString *Over = NSLocalizedString(@"Over", @"Indicates an exceeding number");
NSString *Almost = NSLocalizedString(@"Almost", @"Indicates an approaching number");
//NSString *Second = NSLocalizedString(@"second", @"One second in time");
NSString *Seconds = NSLocalizedString(@"seconds", @"More than one second in time");
NSString *Minute = NSLocalizedString(@"minute", @"One minute in time");
NSString *Minutes = NSLocalizedString(@"minutes", @"More than one minute in time");
NSString *Hour = NSLocalizedString(@"hour", @"One hour in time");
NSString *Hours = NSLocalizedString(@"hours", @"More than one hour in time");
NSString *Day = NSLocalizedString(@"day", @"One day in time");
NSString *Days = NSLocalizedString(@"days", @"More than one day in time");
NSString *Month = NSLocalizedString(@"month", @"One month in time");
NSString *Months = NSLocalizedString(@"months", @"More than one month in time");
NSString *Year = NSLocalizedString(@"year", @"One year in time");
NSString *Years = NSLocalizedString(@"years", @"More than one year in time");

NSUInteger allOptionsEnabledByDefault =
kDOTIWStringComponentModifier |
kDOTIWStringComponentNumber |
kDOTIWStringComponentMeasure |
kDOTIWStringComponentDirection;

return [self distanceOfTimeInWords:date withOptions:allOptionsEnabledByDefault];
}

- (NSString *)distanceOfTimeInWordsWithOptions:(NSUInteger)options {
return [self distanceOfTimeInWords:[NSDate date] withOptions:options];
}

- (NSString *)distanceOfTimeInWords:(NSDate *)date withOptions:(NSUInteger)options {

if (options & kDOTIWStringComponentJustNow)
if (fabs([self timeIntervalSinceDate:date]) < SECONDS_JUST_NOW_LIMIT)
return NSLocalizedStringFromTable(@"Just now", LOCALIZED_STRING_TABLE_NAME, @"Indicates a recent action");

NSString *Ago = NSLocalizedStringFromTable(@"ago", LOCALIZED_STRING_TABLE_NAME, @"Denotes past dates");
NSString *FromNow = NSLocalizedStringFromTable(@"from now", LOCALIZED_STRING_TABLE_NAME, @"Denotes future dates");
NSString *LessThan = NSLocalizedStringFromTable(@"Less than", LOCALIZED_STRING_TABLE_NAME, @"Indicates a less-than number");
NSString *About = NSLocalizedStringFromTable(@"About", LOCALIZED_STRING_TABLE_NAME, @"Indicates an approximate number");
NSString *Over = NSLocalizedStringFromTable(@"Over", LOCALIZED_STRING_TABLE_NAME, @"Indicates an exceeding number");
NSString *Almost = NSLocalizedStringFromTable(@"Almost", LOCALIZED_STRING_TABLE_NAME, @"Indicates an approaching number");
//NSString *Second = NSLocalizedStringFromTable(@"second", LOCALIZED_STRING_TABLE_NAME, @"One second in time");
NSString *Seconds = NSLocalizedStringFromTable(@"seconds", LOCALIZED_STRING_TABLE_NAME, @"More than one second in time");
NSString *Minute = NSLocalizedStringFromTable(@"minute", LOCALIZED_STRING_TABLE_NAME, @"One minute in time");
NSString *Minutes = NSLocalizedStringFromTable(@"minutes", LOCALIZED_STRING_TABLE_NAME, @"More than one minute in time");
NSString *Hour = NSLocalizedStringFromTable(@"hour", LOCALIZED_STRING_TABLE_NAME, @"One hour in time");
NSString *Hours = NSLocalizedStringFromTable(@"hours", LOCALIZED_STRING_TABLE_NAME, @"More than one hour in time");
NSString *Day = NSLocalizedStringFromTable(@"day", LOCALIZED_STRING_TABLE_NAME, @"One day in time");
NSString *Days = NSLocalizedStringFromTable(@"days", LOCALIZED_STRING_TABLE_NAME, @"More than one day in time");
NSString *Month = NSLocalizedStringFromTable(@"month", LOCALIZED_STRING_TABLE_NAME, @"One month in time");
NSString *Months = NSLocalizedStringFromTable(@"months", LOCALIZED_STRING_TABLE_NAME, @"More than one month in time");
NSString *Year = NSLocalizedStringFromTable(@"year", LOCALIZED_STRING_TABLE_NAME, @"One year in time");
NSString *Years = NSLocalizedStringFromTable(@"years", LOCALIZED_STRING_TABLE_NAME, @"More than one year in time");

NSTimeInterval since = [self timeIntervalSinceDate:date];
NSString *direction = since <= 0.0 ? Ago : FromNow;
Expand Down Expand Up @@ -166,7 +189,19 @@ - (NSString *)distanceOfTimeInWords:(NSDate *)date {
if ([modifier length] > 0) {
modifier = [modifier stringByAppendingString:@" "];
}
return [NSString stringWithFormat:@"%@%d %@ %@", modifier, number, measure, direction];

NSMutableString *resultString = [NSMutableString string];

if (options & kDOTIWStringComponentModifier)
[resultString appendString:[NSString stringWithFormat:@"%@", modifier]];
if (options & kDOTIWStringComponentNumber)
[resultString appendString:[NSString stringWithFormat:@"%d", number]];
if (options & kDOTIWStringComponentMeasure)
[resultString appendString:[NSString stringWithFormat:@" %@", measure]];
if (options & kDOTIWStringComponentDirection)
[resultString appendString:[NSString stringWithFormat:@" %@", direction]];

return resultString;
}

@end
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,41 @@ The next two relate to each other. Calling `distanceOfTimeInWords` with no param
* `[[NSDate date] distanceOfTimeInWords];`
* `[[NSDate date] distanceOfTimeInWords:[[NSDate date] dateByAddingTimeInterval:86400]];`

Formatting date strings
----------------------------
These two methods are now available for formatting resulting date strings:

* `- (NSString *)distanceOfTimeInWordsWithOptions:(NSUInteger)options;`
* `- (NSString *)distanceOfTimeInWords:(NSDate *)date withOptions:(NSUInteger)options;`

Both presented methods are accepting a bitmask formed with the following options:

- kDOTIWStringComponentModifier;
- kDOTIWStringComponentNumber;
- kDOTIWStringComponentMeasure;
- kDOTIWStringComponentDirection;
- kDOTIWStringComponentJustNow; `Disabled by default.`

For instance:

[[NSDate date] distanceOfTimeInWords];

Results "`Less than 5 seconds ago`".

NSUInteger dotiwOptions = kDOTIWStringComponentNumber | kDOTIWStringComponentMeasure;

[[NSDate date] distanceOfTimeInWordsWithOptions:dotiwOptions]

Results "`5 seconds`".

dotiwOptions = kDOTIWStringComponentNumber | kDOTIWStringComponentMeasure | kDOTIWStringComponentJustNow;

[[NSDate date] distanceOfTimeInWordsWithOptions:dotiwOptions]

[[NSDate dateWithTimeInterval:10.0 sinceDate:oldDate] distanceOfTimeInWords:oldDate withOptions:options];

Results "`Just now`" for the first call and "`10 seconds`" for the second call (i.e., the `kDOTIWStringComponentJustNow` component overrides others while the time interval between the defined dates (e.g. the received date and oldDate) is smaller than 5 (five) seconds).

Localization
------------
`NSDate+Formatting` uses localized strings, so if you localize your app and provide strings for all that `NSDate+Formatting` uses, your returned string will be localized. The app provides both english and Spanish localizations.
`NSDate+Formatting` uses localized strings, so if you localize your app and provide strings for all that `NSDate+Formatting` uses, your returned string will be localized. The app provides English, Spanish, Chinese and Portuguese localizations.