├── .gitignore ├── ExampleProject ├── ExampleProject.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── ExampleProject │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── ViewController.swift └── ExampleProjectTests │ ├── ExampleProjectTests.swift │ └── Info.plist ├── LICENSE ├── Pods ├── Manifest.lock └── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ └── daniele.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── README.md ├── SwiftDate.podspec ├── SwiftDate └── SwiftDate.swift └── assets └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Created by https://www.gitignore.io 4 | 5 | ### Xcode ### 6 | build/ 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | xcuserdata 16 | *.xccheckout 17 | *.moved-aside 18 | DerivedData 19 | *.xcuserstate -------------------------------------------------------------------------------- /ExampleProject/ExampleProject.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 509419171B0E81700065014B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509419161B0E81700065014B /* AppDelegate.swift */; }; 11 | 509419191B0E81700065014B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509419181B0E81700065014B /* ViewController.swift */; }; 12 | 5094191C1B0E81700065014B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5094191A1B0E81700065014B /* Main.storyboard */; }; 13 | 5094191E1B0E81700065014B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5094191D1B0E81700065014B /* Images.xcassets */; }; 14 | 509419211B0E81700065014B /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5094191F1B0E81700065014B /* LaunchScreen.xib */; }; 15 | 5094192D1B0E81700065014B /* ExampleProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5094192C1B0E81700065014B /* ExampleProjectTests.swift */; }; 16 | 5094193A1B0F71FB0065014B /* SwiftDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509419391B0F71FB0065014B /* SwiftDate.swift */; }; 17 | 5094193B1B0F72330065014B /* SwiftDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509419391B0F71FB0065014B /* SwiftDate.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 509419271B0E81700065014B /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 509419091B0E81700065014B /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 509419101B0E81700065014B; 26 | remoteInfo = ExampleProject; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 509419111B0E81700065014B /* ExampleProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 509419151B0E81700065014B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 509419161B0E81700065014B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 34 | 509419181B0E81700065014B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 35 | 5094191B1B0E81700065014B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 36 | 5094191D1B0E81700065014B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 37 | 509419201B0E81700065014B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 38 | 509419261B0E81700065014B /* ExampleProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 5094192B1B0E81700065014B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 5094192C1B0E81700065014B /* ExampleProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleProjectTests.swift; sourceTree = ""; }; 41 | 509419391B0F71FB0065014B /* SwiftDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftDate.swift; path = ../../SwiftDate/SwiftDate.swift; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 5094190E1B0E81700065014B /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | 509419231B0E81700065014B /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 509419081B0E81700065014B = { 63 | isa = PBXGroup; 64 | children = ( 65 | 509419131B0E81700065014B /* ExampleProject */, 66 | 509419291B0E81700065014B /* ExampleProjectTests */, 67 | 509419121B0E81700065014B /* Products */, 68 | ); 69 | sourceTree = ""; 70 | }; 71 | 509419121B0E81700065014B /* Products */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 509419111B0E81700065014B /* ExampleProject.app */, 75 | 509419261B0E81700065014B /* ExampleProjectTests.xctest */, 76 | ); 77 | name = Products; 78 | sourceTree = ""; 79 | }; 80 | 509419131B0E81700065014B /* ExampleProject */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 509419391B0F71FB0065014B /* SwiftDate.swift */, 84 | 509419161B0E81700065014B /* AppDelegate.swift */, 85 | 509419181B0E81700065014B /* ViewController.swift */, 86 | 5094191A1B0E81700065014B /* Main.storyboard */, 87 | 5094191D1B0E81700065014B /* Images.xcassets */, 88 | 5094191F1B0E81700065014B /* LaunchScreen.xib */, 89 | 509419141B0E81700065014B /* Supporting Files */, 90 | ); 91 | path = ExampleProject; 92 | sourceTree = ""; 93 | }; 94 | 509419141B0E81700065014B /* Supporting Files */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 509419151B0E81700065014B /* Info.plist */, 98 | ); 99 | name = "Supporting Files"; 100 | sourceTree = ""; 101 | }; 102 | 509419291B0E81700065014B /* ExampleProjectTests */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 5094192C1B0E81700065014B /* ExampleProjectTests.swift */, 106 | 5094192A1B0E81700065014B /* Supporting Files */, 107 | ); 108 | path = ExampleProjectTests; 109 | sourceTree = ""; 110 | }; 111 | 5094192A1B0E81700065014B /* Supporting Files */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 5094192B1B0E81700065014B /* Info.plist */, 115 | ); 116 | name = "Supporting Files"; 117 | sourceTree = ""; 118 | }; 119 | /* End PBXGroup section */ 120 | 121 | /* Begin PBXNativeTarget section */ 122 | 509419101B0E81700065014B /* ExampleProject */ = { 123 | isa = PBXNativeTarget; 124 | buildConfigurationList = 509419301B0E81700065014B /* Build configuration list for PBXNativeTarget "ExampleProject" */; 125 | buildPhases = ( 126 | 5094190D1B0E81700065014B /* Sources */, 127 | 5094190E1B0E81700065014B /* Frameworks */, 128 | 5094190F1B0E81700065014B /* Resources */, 129 | ); 130 | buildRules = ( 131 | ); 132 | dependencies = ( 133 | ); 134 | name = ExampleProject; 135 | productName = ExampleProject; 136 | productReference = 509419111B0E81700065014B /* ExampleProject.app */; 137 | productType = "com.apple.product-type.application"; 138 | }; 139 | 509419251B0E81700065014B /* ExampleProjectTests */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 509419331B0E81700065014B /* Build configuration list for PBXNativeTarget "ExampleProjectTests" */; 142 | buildPhases = ( 143 | 509419221B0E81700065014B /* Sources */, 144 | 509419231B0E81700065014B /* Frameworks */, 145 | 509419241B0E81700065014B /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | 509419281B0E81700065014B /* PBXTargetDependency */, 151 | ); 152 | name = ExampleProjectTests; 153 | productName = ExampleProjectTests; 154 | productReference = 509419261B0E81700065014B /* ExampleProjectTests.xctest */; 155 | productType = "com.apple.product-type.bundle.unit-test"; 156 | }; 157 | /* End PBXNativeTarget section */ 158 | 159 | /* Begin PBXProject section */ 160 | 509419091B0E81700065014B /* Project object */ = { 161 | isa = PBXProject; 162 | attributes = { 163 | LastSwiftUpdateCheck = 0700; 164 | LastUpgradeCheck = 0700; 165 | TargetAttributes = { 166 | 509419101B0E81700065014B = { 167 | CreatedOnToolsVersion = 6.3.2; 168 | }; 169 | 509419251B0E81700065014B = { 170 | CreatedOnToolsVersion = 6.3.2; 171 | TestTargetID = 509419101B0E81700065014B; 172 | }; 173 | }; 174 | }; 175 | buildConfigurationList = 5094190C1B0E81700065014B /* Build configuration list for PBXProject "ExampleProject" */; 176 | compatibilityVersion = "Xcode 3.2"; 177 | developmentRegion = English; 178 | hasScannedForEncodings = 0; 179 | knownRegions = ( 180 | en, 181 | Base, 182 | ); 183 | mainGroup = 509419081B0E81700065014B; 184 | productRefGroup = 509419121B0E81700065014B /* Products */; 185 | projectDirPath = ""; 186 | projectRoot = ""; 187 | targets = ( 188 | 509419101B0E81700065014B /* ExampleProject */, 189 | 509419251B0E81700065014B /* ExampleProjectTests */, 190 | ); 191 | }; 192 | /* End PBXProject section */ 193 | 194 | /* Begin PBXResourcesBuildPhase section */ 195 | 5094190F1B0E81700065014B /* Resources */ = { 196 | isa = PBXResourcesBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | 5094191C1B0E81700065014B /* Main.storyboard in Resources */, 200 | 509419211B0E81700065014B /* LaunchScreen.xib in Resources */, 201 | 5094191E1B0E81700065014B /* Images.xcassets in Resources */, 202 | ); 203 | runOnlyForDeploymentPostprocessing = 0; 204 | }; 205 | 509419241B0E81700065014B /* Resources */ = { 206 | isa = PBXResourcesBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXResourcesBuildPhase section */ 213 | 214 | /* Begin PBXSourcesBuildPhase section */ 215 | 5094190D1B0E81700065014B /* Sources */ = { 216 | isa = PBXSourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | 509419191B0E81700065014B /* ViewController.swift in Sources */, 220 | 5094193A1B0F71FB0065014B /* SwiftDate.swift in Sources */, 221 | 509419171B0E81700065014B /* AppDelegate.swift in Sources */, 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | }; 225 | 509419221B0E81700065014B /* Sources */ = { 226 | isa = PBXSourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | 5094193B1B0F72330065014B /* SwiftDate.swift in Sources */, 230 | 5094192D1B0E81700065014B /* ExampleProjectTests.swift in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXTargetDependency section */ 237 | 509419281B0E81700065014B /* PBXTargetDependency */ = { 238 | isa = PBXTargetDependency; 239 | target = 509419101B0E81700065014B /* ExampleProject */; 240 | targetProxy = 509419271B0E81700065014B /* PBXContainerItemProxy */; 241 | }; 242 | /* End PBXTargetDependency section */ 243 | 244 | /* Begin PBXVariantGroup section */ 245 | 5094191A1B0E81700065014B /* Main.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 5094191B1B0E81700065014B /* Base */, 249 | ); 250 | name = Main.storyboard; 251 | sourceTree = ""; 252 | }; 253 | 5094191F1B0E81700065014B /* LaunchScreen.xib */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | 509419201B0E81700065014B /* Base */, 257 | ); 258 | name = LaunchScreen.xib; 259 | sourceTree = ""; 260 | }; 261 | /* End PBXVariantGroup section */ 262 | 263 | /* Begin XCBuildConfiguration section */ 264 | 5094192E1B0E81700065014B /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 269 | CLANG_CXX_LIBRARY = "libc++"; 270 | CLANG_ENABLE_MODULES = YES; 271 | CLANG_ENABLE_OBJC_ARC = YES; 272 | CLANG_WARN_BOOL_CONVERSION = YES; 273 | CLANG_WARN_CONSTANT_CONVERSION = YES; 274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INT_CONVERSION = YES; 278 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 282 | COPY_PHASE_STRIP = NO; 283 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 284 | ENABLE_STRICT_OBJC_MSGSEND = YES; 285 | ENABLE_TESTABILITY = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_DYNAMIC_NO_PIC = NO; 288 | GCC_NO_COMMON_BLOCKS = YES; 289 | GCC_OPTIMIZATION_LEVEL = 0; 290 | GCC_PREPROCESSOR_DEFINITIONS = ( 291 | "DEBUG=1", 292 | "$(inherited)", 293 | ); 294 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 296 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 297 | GCC_WARN_UNDECLARED_SELECTOR = YES; 298 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 299 | GCC_WARN_UNUSED_FUNCTION = YES; 300 | GCC_WARN_UNUSED_VARIABLE = YES; 301 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 302 | MTL_ENABLE_DEBUG_INFO = YES; 303 | ONLY_ACTIVE_ARCH = YES; 304 | SDKROOT = iphoneos; 305 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 306 | TARGETED_DEVICE_FAMILY = "1,2"; 307 | }; 308 | name = Debug; 309 | }; 310 | 5094192F1B0E81700065014B /* Release */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ALWAYS_SEARCH_USER_PATHS = NO; 314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 315 | CLANG_CXX_LIBRARY = "libc++"; 316 | CLANG_ENABLE_MODULES = YES; 317 | CLANG_ENABLE_OBJC_ARC = YES; 318 | CLANG_WARN_BOOL_CONVERSION = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 321 | CLANG_WARN_EMPTY_BODY = YES; 322 | CLANG_WARN_ENUM_CONVERSION = YES; 323 | CLANG_WARN_INT_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_UNREACHABLE_CODE = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 328 | COPY_PHASE_STRIP = NO; 329 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 330 | ENABLE_NS_ASSERTIONS = NO; 331 | ENABLE_STRICT_OBJC_MSGSEND = YES; 332 | GCC_C_LANGUAGE_STANDARD = gnu99; 333 | GCC_NO_COMMON_BLOCKS = YES; 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 341 | MTL_ENABLE_DEBUG_INFO = NO; 342 | SDKROOT = iphoneos; 343 | TARGETED_DEVICE_FAMILY = "1,2"; 344 | VALIDATE_PRODUCT = YES; 345 | }; 346 | name = Release; 347 | }; 348 | 509419311B0E81700065014B /* Debug */ = { 349 | isa = XCBuildConfiguration; 350 | buildSettings = { 351 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 352 | INFOPLIST_FILE = ExampleProject/Info.plist; 353 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 354 | PRODUCT_BUNDLE_IDENTIFIER = "com.swiftdate.$(PRODUCT_NAME:rfc1034identifier)"; 355 | PRODUCT_NAME = "$(TARGET_NAME)"; 356 | SDKROOT = iphoneos; 357 | }; 358 | name = Debug; 359 | }; 360 | 509419321B0E81700065014B /* Release */ = { 361 | isa = XCBuildConfiguration; 362 | buildSettings = { 363 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 364 | INFOPLIST_FILE = ExampleProject/Info.plist; 365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 366 | PRODUCT_BUNDLE_IDENTIFIER = "com.swiftdate.$(PRODUCT_NAME:rfc1034identifier)"; 367 | PRODUCT_NAME = "$(TARGET_NAME)"; 368 | SDKROOT = iphoneos; 369 | }; 370 | name = Release; 371 | }; 372 | 509419341B0E81700065014B /* Debug */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | BUNDLE_LOADER = "$(TEST_HOST)"; 376 | FRAMEWORK_SEARCH_PATHS = ( 377 | "$(SDKROOT)/Developer/Library/Frameworks", 378 | "$(inherited)", 379 | ); 380 | GCC_PREPROCESSOR_DEFINITIONS = ( 381 | "DEBUG=1", 382 | "$(inherited)", 383 | ); 384 | INFOPLIST_FILE = ExampleProjectTests/Info.plist; 385 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 386 | PRODUCT_BUNDLE_IDENTIFIER = "com.swiftdate.$(PRODUCT_NAME:rfc1034identifier)"; 387 | PRODUCT_NAME = "$(TARGET_NAME)"; 388 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ExampleProject.app/ExampleProject"; 389 | }; 390 | name = Debug; 391 | }; 392 | 509419351B0E81700065014B /* Release */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | BUNDLE_LOADER = "$(TEST_HOST)"; 396 | FRAMEWORK_SEARCH_PATHS = ( 397 | "$(SDKROOT)/Developer/Library/Frameworks", 398 | "$(inherited)", 399 | ); 400 | INFOPLIST_FILE = ExampleProjectTests/Info.plist; 401 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 402 | PRODUCT_BUNDLE_IDENTIFIER = "com.swiftdate.$(PRODUCT_NAME:rfc1034identifier)"; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ExampleProject.app/ExampleProject"; 405 | }; 406 | name = Release; 407 | }; 408 | /* End XCBuildConfiguration section */ 409 | 410 | /* Begin XCConfigurationList section */ 411 | 5094190C1B0E81700065014B /* Build configuration list for PBXProject "ExampleProject" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 5094192E1B0E81700065014B /* Debug */, 415 | 5094192F1B0E81700065014B /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | 509419301B0E81700065014B /* Build configuration list for PBXNativeTarget "ExampleProject" */ = { 421 | isa = XCConfigurationList; 422 | buildConfigurations = ( 423 | 509419311B0E81700065014B /* Debug */, 424 | 509419321B0E81700065014B /* Release */, 425 | ); 426 | defaultConfigurationIsVisible = 0; 427 | defaultConfigurationName = Release; 428 | }; 429 | 509419331B0E81700065014B /* Build configuration list for PBXNativeTarget "ExampleProjectTests" */ = { 430 | isa = XCConfigurationList; 431 | buildConfigurations = ( 432 | 509419341B0E81700065014B /* Debug */, 433 | 509419351B0E81700065014B /* Release */, 434 | ); 435 | defaultConfigurationIsVisible = 0; 436 | defaultConfigurationName = Release; 437 | }; 438 | /* End XCConfigurationList section */ 439 | }; 440 | rootObject = 509419091B0E81700065014B /* Project object */; 441 | } 442 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProject/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ExampleProject 4 | // 5 | // Created by Mark Norgren on 5/21/15. 6 | // 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProject/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProject/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProject/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /ExampleProject/ExampleProject/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.swiftdate.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProject/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ExampleProject 4 | // 5 | // Created by Mark Norgren on 5/21/15. 6 | // 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | class ViewController: UIViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | let date = NSDate() 18 | 19 | _ = date.toString(format: DateFormat.Custom("YYYY-MM-DD")) 20 | 21 | 22 | _ = date+1.day 23 | let two_months_ago = date-2.months 24 | print(two_months_ago.toLongDateString()) 25 | 26 | 27 | 28 | let date_as_utc = date.toUTC() //UTC 时间 29 | let date_as_beijing = date_as_utc.toTimezone("GMT+0800") //北京时间 30 | 31 | print(date_as_utc.toLongTimeString()) 32 | print(date_as_beijing?.toLongTimeString()) 33 | 34 | let d = NSDate()-1.hour 35 | 36 | print(d.year) 37 | 38 | 39 | let date1 = NSDate.date(fromString: "2015-07-26", format: DateFormat.Custom("YYYY-MM-DD")) 40 | let date2 = NSDate.date(fromString: "2015-07-27", format: DateFormat.Custom("YYYY-MM-DD")) 41 | 42 | if date2 > date1 { 43 | 44 | // TODO something 45 | print("Hello") 46 | 47 | } 48 | 49 | 50 | let abb = d.toRelativeString(abbreviated: true, maxUnits: 3) 51 | print("data: \(abb)") 52 | // 53 | // let w = NSDate()-1.month 54 | // print("Prev month: \(w)") 55 | // 56 | // var w2 = NSDate().add("month",value:-1) 57 | // print(date) 58 | } 59 | 60 | override func didReceiveMemoryWarning() { 61 | super.didReceiveMemoryWarning() 62 | // Dispose of any resources that can be recreated. 63 | } 64 | 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProjectTests/ExampleProjectTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleProjectTests.swift 3 | // ExampleProjectTests 4 | // 5 | // Created by Mark Norgren on 5/21/15. 6 | // 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class ExampleProjectTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testISO8601_Year() { 25 | let dateString = "1983" 26 | let date = dateString.toDate(format: DateFormat.ISO8601) 27 | let dateFormatter = NSDateFormatter() 28 | dateFormatter.dateFormat = "yyyy" 29 | let controlDate = dateFormatter.dateFromString(dateString) 30 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 31 | } 32 | 33 | // dateFormatter = "yyyy-MM" 34 | func testISO8601_YearMonth() { 35 | let dateString = "1983-03" 36 | let date = dateString.toDate(format: DateFormat.ISO8601) 37 | let dateFormatter = NSDateFormatter() 38 | dateFormatter.dateFormat = "yyyy-MM" 39 | let controlDate = dateFormatter.dateFromString(dateString) 40 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 41 | } 42 | // dateFormatter = "yyyy-MM-DD" 43 | func testISO8601_YearMonthDay() { 44 | let dateString = "1983-03-10" 45 | let date = dateString.toDate(format: DateFormat.ISO8601) 46 | let dateFormatter = NSDateFormatter() 47 | dateFormatter.dateFormat = "yyyy-MM-dd" 48 | let controlDate = dateFormatter.dateFromString(dateString) 49 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 50 | } 51 | // dateFormatter = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 52 | func testISO8601_YearMonthDayHoursMinutes() { 53 | let dateString = "1997-07-16T19:20+01:00" 54 | let date = dateString.toDate(format: DateFormat.ISO8601) 55 | let dateFormatter = NSDateFormatter() 56 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mmZ" 57 | let controlDate = dateFormatter.dateFromString(dateString) 58 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 59 | } 60 | // "yyyy-MM-dd'T'HH:mm:ssZ" 61 | func testISO8601_YearMonthDayHoursMinutesSeconds() { 62 | let dateString = "1997-07-16T19:20:30+01:00" 63 | let date = dateString.toDate(format: DateFormat.ISO8601) 64 | let dateFormatter = NSDateFormatter() 65 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" 66 | let controlDate = dateFormatter.dateFromString(dateString) 67 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 68 | } 69 | // "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 70 | func testISO8601_YearMonthDayHoursMinutesSecondsFractionOfSecondTwoPlaces() { 71 | let dateString = "1997-07-16T19:20:30.45+01:00" 72 | let date = dateString.toDate(format: DateFormat.ISO8601) 73 | let dateFormatter = NSDateFormatter() 74 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 75 | let controlDate = dateFormatter.dateFromString(dateString) 76 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 77 | } 78 | // "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 79 | func testISO8601_YearMonthDayHoursMinutesSecondsFractionOfSecondThreePlaces() { 80 | let dateString = "1997-07-16T19:20:30.456+01:00" 81 | let date = dateString.toDate(format: DateFormat.ISO8601) 82 | let dateFormatter = NSDateFormatter() 83 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 84 | let controlDate = dateFormatter.dateFromString(dateString) 85 | XCTAssertEqual(date!, controlDate!, "SwiftDate should equal controlDate") 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /ExampleProject/ExampleProjectTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.swiftdate.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Daniele Margutti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | COCOAPODS: 0.37.0 2 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXFileReference section */ 10 | 6E117ED054A8D52D7B6DCAAD /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 11 | /* End PBXFileReference section */ 12 | 13 | /* Begin PBXGroup section */ 14 | 1B60A143D35D4B314420AFE0 /* Products */ = { 15 | isa = PBXGroup; 16 | children = ( 17 | ); 18 | name = Products; 19 | sourceTree = ""; 20 | }; 21 | 1F48ED0D56BEC957A8490616 = { 22 | isa = PBXGroup; 23 | children = ( 24 | 6E117ED054A8D52D7B6DCAAD /* Podfile */, 25 | FBB43679C12E573BC23E4340 /* Frameworks */, 26 | 1B60A143D35D4B314420AFE0 /* Products */, 27 | CA268F7C30DF903AF8ED0791 /* Targets Support Files */, 28 | ); 29 | sourceTree = ""; 30 | }; 31 | CA268F7C30DF903AF8ED0791 /* Targets Support Files */ = { 32 | isa = PBXGroup; 33 | children = ( 34 | ); 35 | name = "Targets Support Files"; 36 | sourceTree = ""; 37 | }; 38 | FBB43679C12E573BC23E4340 /* Frameworks */ = { 39 | isa = PBXGroup; 40 | children = ( 41 | ); 42 | name = Frameworks; 43 | sourceTree = ""; 44 | }; 45 | /* End PBXGroup section */ 46 | 47 | /* Begin PBXProject section */ 48 | 324A6A8E47D2785C62304877 /* Project object */ = { 49 | isa = PBXProject; 50 | attributes = { 51 | LastUpgradeCheck = 0640; 52 | }; 53 | buildConfigurationList = 09C22649098BADF4841D16B7 /* Build configuration list for PBXProject "Pods" */; 54 | compatibilityVersion = "Xcode 3.2"; 55 | developmentRegion = English; 56 | hasScannedForEncodings = 0; 57 | knownRegions = ( 58 | en, 59 | ); 60 | mainGroup = 1F48ED0D56BEC957A8490616; 61 | productRefGroup = 1B60A143D35D4B314420AFE0 /* Products */; 62 | projectDirPath = ""; 63 | projectRoot = ""; 64 | targets = ( 65 | ); 66 | }; 67 | /* End PBXProject section */ 68 | 69 | /* Begin XCBuildConfiguration section */ 70 | 281DD5E6283D6864B1744E8C /* Debug */ = { 71 | isa = XCBuildConfiguration; 72 | buildSettings = { 73 | ALWAYS_SEARCH_USER_PATHS = NO; 74 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 75 | CLANG_CXX_LIBRARY = "libc++"; 76 | CLANG_ENABLE_MODULES = YES; 77 | CLANG_ENABLE_OBJC_ARC = YES; 78 | CLANG_WARN_BOOL_CONVERSION = YES; 79 | CLANG_WARN_CONSTANT_CONVERSION = YES; 80 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; 81 | CLANG_WARN_EMPTY_BODY = YES; 82 | CLANG_WARN_ENUM_CONVERSION = YES; 83 | CLANG_WARN_INT_CONVERSION = YES; 84 | CLANG_WARN_OBJC_ROOT_CLASS = YES; 85 | CLANG_WARN_UNREACHABLE_CODE = YES; 86 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 87 | COPY_PHASE_STRIP = NO; 88 | GCC_C_LANGUAGE_STANDARD = gnu99; 89 | GCC_DYNAMIC_NO_PIC = NO; 90 | GCC_OPTIMIZATION_LEVEL = 0; 91 | GCC_PREPROCESSOR_DEFINITIONS = ( 92 | "DEBUG=1", 93 | "$(inherited)", 94 | ); 95 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 96 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 97 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 98 | GCC_WARN_UNDECLARED_SELECTOR = YES; 99 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 100 | GCC_WARN_UNUSED_FUNCTION = YES; 101 | GCC_WARN_UNUSED_VARIABLE = YES; 102 | MACOSX_DEPLOYMENT_TARGET = 10.9; 103 | ONLY_ACTIVE_ARCH = YES; 104 | STRIP_INSTALLED_PRODUCT = NO; 105 | SYMROOT = "${SRCROOT}/../build"; 106 | }; 107 | name = Debug; 108 | }; 109 | 3173A826E79D16F1F5246795 /* Release */ = { 110 | isa = XCBuildConfiguration; 111 | buildSettings = { 112 | ALWAYS_SEARCH_USER_PATHS = NO; 113 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 114 | CLANG_CXX_LIBRARY = "libc++"; 115 | CLANG_ENABLE_MODULES = YES; 116 | CLANG_ENABLE_OBJC_ARC = YES; 117 | CLANG_WARN_BOOL_CONVERSION = YES; 118 | CLANG_WARN_CONSTANT_CONVERSION = YES; 119 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; 120 | CLANG_WARN_EMPTY_BODY = YES; 121 | CLANG_WARN_ENUM_CONVERSION = YES; 122 | CLANG_WARN_INT_CONVERSION = YES; 123 | CLANG_WARN_OBJC_ROOT_CLASS = YES; 124 | CLANG_WARN_UNREACHABLE_CODE = YES; 125 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 126 | COPY_PHASE_STRIP = YES; 127 | ENABLE_NS_ASSERTIONS = NO; 128 | GCC_C_LANGUAGE_STANDARD = gnu99; 129 | GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1"; 130 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 131 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 132 | GCC_WARN_UNDECLARED_SELECTOR = YES; 133 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 134 | GCC_WARN_UNUSED_FUNCTION = YES; 135 | GCC_WARN_UNUSED_VARIABLE = YES; 136 | MACOSX_DEPLOYMENT_TARGET = 10.9; 137 | STRIP_INSTALLED_PRODUCT = NO; 138 | SYMROOT = "${SRCROOT}/../build"; 139 | VALIDATE_PRODUCT = YES; 140 | }; 141 | name = Release; 142 | }; 143 | /* End XCBuildConfiguration section */ 144 | 145 | /* Begin XCConfigurationList section */ 146 | 09C22649098BADF4841D16B7 /* Build configuration list for PBXProject "Pods" */ = { 147 | isa = XCConfigurationList; 148 | buildConfigurations = ( 149 | 281DD5E6283D6864B1744E8C /* Debug */, 150 | 3173A826E79D16F1F5246795 /* Release */, 151 | ); 152 | defaultConfigurationIsVisible = 0; 153 | defaultConfigurationName = Release; 154 | }; 155 | /* End XCConfigurationList section */ 156 | }; 157 | rootObject = 324A6A8E47D2785C62304877 /* Project object */; 158 | } 159 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SuppressBuildableAutocreation 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![SwiftDate](https://raw.githubusercontent.com/malcommac/SwiftDate/master/assets/logo.png) 2 | 3 | 4 | 注意:本版本已改为支持Swift2.0,请在Xcode7中使用,无法兼容Swift1.2。 5 | 6 | ##Easy NSDate Management in Swift 7 | 8 | ### Author 9 | Daniele Margutti 10 | *web*: [www.danielemargutti.com](http://www.danielemargutti.com) 11 | *twitter*: [@danielemargutti](http://www.twitter.com/danielemargutti) 12 | *mail*: me [at] danielemargutti dot com 13 | *original post*: [blog](http://danielemargutti.com/how-to-manage-nsdate-easily-in-swift-with-swiftdate/) 14 | 15 | This library is licensed under MIT license and it's compatible with Swift 1.2. 16 | 17 | ###Features 18 | - [x] Math operations with dates ```(ie. myDate+2.week+1.hour)``` 19 | - [x] Easy compare using ```<,>,==,<=,>=``` operators 20 | - [x] Easy individual date component set/get 21 | - [x] Easy creation with common formats or custom formats 22 | - [x] Powerful .toString methods with support for relative dates (ie. "2hours"...) 23 | - [x] Many shortcuts to get intervals and common dates (yesterday,tomorrow...) 24 | - [x] *... check out documentation below!* 25 | 26 | ###Requirements 27 | * iOS 8.0+ / Mac OS X 10.10+ 28 | * Xcode 7.0 29 | * Swift 2.0 30 | 31 | ## Communication 32 | - If you **found a bug**, open an issue. 33 | - If you **have a feature request**, open an issue. 34 | - If you **want to contribute**, submit a pull request. 35 | 36 | ## ToDo 37 | - Unit Test Project 38 | 39 | ### CocoaPods 40 | 41 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. 42 | CocoaPods 0.36 adds supports for Swift and embedded frameworks. You can install it with the following command: 43 | 44 | ```bash 45 | $ gem install cocoapods 46 | ``` 47 | 48 | To integrate SwiftDate into your Xcode project using CocoaPods, specify it in your `Podfile`: 49 | 50 | ```ruby 51 | source 'https://github.com/CocoaPods/Specs.git' 52 | platform :ios, '8.0' 53 | use_frameworks! 54 | 55 | pod 'SwiftDate' 56 | ``` 57 | 58 | Then, run the following command: 59 | 60 | ```bash 61 | $ pod install 62 | ``` 63 | 64 | ##API Documentation 65 | 66 | ###Introduction 67 | Date Management in UIKit/AppKit is a pain, you know? Probably it's not the better API bought by Apple for Mac or iOS. If you have worked in ObjC you know, there are lots of classes to manipulate date objects easily. 68 | I've made SwiftDates because I've started working with Swift development and I need something which save to me with Date during the development. 69 | SwiftDates is extremly portable; in fact it's a single compact file which add several methods and properties both NSDate and String objects. 70 | You will like it :-) ... or fork it! 71 | 72 | ###Create new NSDate objects 73 | You can create a new NSDate objects by passing a String (and optionally a format) or setting each component individually. 74 | ```swift 75 | let date_iso8601 = NSDate.date(fromString: "2015-01-05T22:10:55.200Z", format: DateFormat.ISO8601) 76 | let date_rss = NSDate.date(fromString: "Fri, 09 Sep 2011 15:26:08 +0200", format: DateFormat.RSS) 77 | let date_altrss = NSDate.date(fromString: "09 Sep 2011 15:26:08 +0200", format: DateFormat.AltRSS) 78 | let date_custom = NSDate.date(fromString: "22/01/2015", format: DateFormat.Custom("DD/MM/YYYY")) 79 | ``` 80 | You can also create a date by specifing indivually each component. 81 | This method accept a reference date to use (just use nil to start with the current NSDate()) and you can pass the components you want to alter (if you don't want to alter the current hour, for example, just pass nil as hour: parameter). 82 | This is an example: suppose current date is 2015/05/01 @ 22:00 83 | By using: 84 | ```swift 85 | let date_from_components = NSDate.date(refDate: nil, year: 2014, month: 01, day: nil, hour: nil, minute: nil, second: nil, tz: "UTC") 86 | ``` 87 | You will have a NSDate which represent 2014/05/01 @ 22:00! 88 | So simple! 89 | 90 | Finally you can create a new date from a String using: 91 | ```swift 92 | let date = "22/01/2015".toDate(formatString: "DD/MM/YYYY") 93 | let date = "2015-01-05T22:10:55.200Z".toDate(format: DateFormat.ISO8601) 94 | ``` 95 | 96 | ###Date Instances Shortcuts 97 | As usual you can get common date instances with the following methods: 98 | 99 | ```swift 100 | let todayDate = NSDate.today() 101 | let yesterdayDate = NSDate.yesterday() 102 | let tomorrowDate = NSDate.tomorrow() 103 | ``` 104 | 105 | ##Get/Alter Individual Date Components 106 | You can get or alter date components too. However NSDate objects are immutable so while you can have access to each unit component via properties I've made several methods to alter individual components (and get a new date instance). 107 | 108 | ### Accessing Date Components 109 | So these are readable properties (and some methods): 110 | ```swift 111 | .year 112 | .month 113 | .weekOfMonth 114 | .weekday 115 | .weekdayOrdinal 116 | .day 117 | .hour 118 | .minute 119 | .second 120 | .era 121 | .firstDayOfWeek // (first day of the week of passed date) 122 | .lastDayOfWeek // (last day of the week of passed date) 123 | .nearestHour // (nearest hour of the passed date) 124 | .isLeapYear() // true if date's represented year is leap 125 | .monthDays() // return the number of days in date's represented month 126 | ``` 127 | 128 | ### Alter Date Components 129 | You can set a new property individually using set method (it accepts year, month, day, hour, minute, second as component name parameter): 130 | ```swift 131 | let date = NSDate() // Suppose it's 2015-01-05 @ 22:00 132 | date = date.set("hour",12) // date will be a new objects which represent 2015-01-05 at 12:00 133 | date = date.set("day",1) // 2015-01-01 @ 12:00 134 | ``` 135 | While you can perfectly chain multiple set, in order to avoid unnecessary objects allocations you can use set method which accept multiple components: 136 | ```swift 137 | let date = NSDate() 138 | date = date.set(year: 2000, month: 01, day: 01, hour:0, minute:0, second:0, tz:nil) 139 | ``` 140 | With a single allocation you have your new object; If you don't want to set a single component just pass nil as value. 141 | Another shortcut involves dictionaries: 142 | ```swift 143 | let date = NSDate() // Suppose it's 2015-01-05 @ 22:00 144 | date = date.set(["hour":12,"minute":55]); // Returns a new NSDate 2015-01-05 @ 12:55 145 | ``` 146 | ### Add/Subtract Components From Date 147 | You can add single components to an existing date very easily: 148 | ```swift 149 | let date = NSDate() 150 | let tomorrow = date+1.day 151 | let 2_months_ago = date-2.months 152 | let next_year_today = date+1.year 153 | let another_date = date+54.seconds 154 | if date1+1.week == date2-1.month { 155 | // some good stuff to do... 156 | } 157 | ``` 158 | (Note: variants +=,-= modify first parameter of the operation) 159 | It's like just doing math! 160 | You can also do it in some more classic ways: 161 | ```swift 162 | let date = NSDate() // Suppose it's 2015-01-05 @ 22:00 163 | let tomorrow = date.add(years: nil, months: nil, days: 1, minutes: nil, seconds: nil) // it will be 2015-01-06 @ 22:00 164 | let next2Hours = date.add("minute",20) // it will be 2016-01-05 @ 22:20 165 | let tomorrowNextYear = date.add(["year":1,"day":1]) // it will be 2016-01-06 @ 22:00 166 | ``` 167 | ### Timezone & Dates 168 | NSDate objects don't have time zones; they represent an absolute moment in time. 169 | However, when you ask one for its description (by printing it in an NSLog, e.g.), it has to pick a time zone. The most reasonable "default" choice is GMT. If you're not in GMT yourself, the date will seem to be incorrect, by the amount of your own offset. 170 | You should always use an NSDateFormatter, setting its timezone to yours, before displaying a date. 171 | Use: 172 | ```swift 173 | let date = NSDate() // Local NSTimeZone date 174 | let date_as_utc = date.toUTC() 175 | let date_as_local = date_as_utc.toLocal() 176 | let date_as_EST = date_as_utc.toTimezone("EST") // convert to Eastern Time timezone 177 | ``` 178 | 179 | ### Compare Dates 180 | Thanks to Swift you can compare dates using intuitive math operators: <,<=,==,>,>=: 181 | So, let me show a simple example 182 | ```swift 183 | let date1 = NSDate.date(fromString: "2015-01-01T00:00:00.000Z", format: DateFormat.ISO8601) 184 | let date2 = NSDate.date(fromString: "2015-01-11T00:00:00.000Z", format: DateFormat.ISO8601) 185 | 186 | if date2 > date1 { ... } // or <= 187 | if date2 == date1 { ... } 188 | if date2 < date1 { ... } // or >= 189 | // and so on... 190 | ``` 191 | You can also compare two dates using: 192 | ```swift 193 | let date1...; let date2...; 194 | let equals : Bool = date1.isEqualToDate(date2, ignoreTime: true) // comparisor is done only at date level, ignoring the time component 195 | ``` 196 | 197 | You can also check if a date time component fall in a time range: 198 | ```swift 199 | let isInRange : Bool = date1.isInTimeRange("11:00","15:00") // true if time component of the date falls inside proposed range (11am-03pm) 200 | ``` 201 | 202 | Some other properties/methods are: 203 | ```swift 204 | .isToday() // true if represented date is today 205 | .isTomorrow() 206 | .isYesterday() 207 | .isThisWeek() // true if represented date's week is the current week 208 | .isSameWeekOf(date: NSDate) // true if two dates share the same year's week 209 | .dateAtWeekStart() // return the date where current's date week starts 210 | .beginningOfDay() // return the same date of the sender with time set to 00:00:00 211 | .endOfDay() // return the same date of the sender with time set to 23:59:59 212 | .beginningOfMonth() // return the date which represent the first day of the sender date's month 213 | .endOfMonth() // return the date which represent the last day of the sender date's month 214 | .beginningOfYear() // return the date which represent the first day of the sender date's year 215 | .endOfYear() // return the date which represent the last day of the sender date's year 216 | .isWeekday() // true if current sender date is a week day 217 | .isWeekend() // true if current sender date is a weekend day (sat/sun) 218 | ``` 219 | ### Intervals 220 | 221 | 222 | ### From NSDate to String 223 | SwiftDate has several interesting methods to convert NSDate instances to string representation. 224 | You can get the string from date using a particular format (don't worry, to preserve performances we use a singleton NSDateFormatter): 225 | ```swift 226 | let string = date.toString(format: DateFormat.Custom("YYYY-MM-DD")) // something like "2015-01-01" 227 | let string = date.toString(format: DateFormat.ISO8601) // something like "2015-01-01T00:00:00.000Z" 228 | let string = date.toISOString() // the same of the above DateFormat.ISO8601 229 | ``` 230 | You can also use convenience methods for NSDateFormatterStyle: 231 | ```swift 232 | let string = date.toString(dateStyle: .ShortStyle timeStyle:.LongStyle relativeDate:true) 233 | ``` 234 | Shortcuts are also available: 235 | ```swift 236 | .toShortString() // short style, both time and date are printed 237 | .toMediumString() // medium style, both time and date are printed 238 | .toLongString() // full style, both time and date are printed 239 | .toShortDateString() // short style, print only date 240 | .toShortTimeString() // short style, print only time 241 | .toMediumDateString() // medium style, print only date 242 | .toMediumTimeString() // medium style, print only time 243 | .toLongDateString() // long style, print only date 244 | .toLongTimeString() // long style, print only time 245 | ``` 246 | 247 | Finally you can also get a relative representation of the string (ie. "2 hours ago", "1 day ago"...) by using: 248 | ```swift 249 | let string = date.toRelativeString(fromDate: nil, abbreviated: false, maxUnits:2) 250 | ``` 251 | This example tell to SwiftDate to return a relative representation of the date by comparing it to the current date (nil in fromDate means NSDate()) without using an abbreviated form (use "seconds" not "secs", or "years" not "ys") and with a max number of units of 2 (this is used to get the approximation units to print, ie "2 hours, 30 minutes" are 2 units, "2 hours, 30 minutes, 5 seconds" are 3 units). 252 | 253 | ### Some other libraries: 254 | SwiftDate was also inspired by other works. 255 | Some links: 256 | * [AFDateHelper](https://github.com/melvitax/AFDateHelper) 257 | * [Timepiece](https://github.com/naoty/Timepiece) 258 | * [MSDateFormatter](https://github.com/Namvt/MSDateFormatter) 259 | -------------------------------------------------------------------------------- /SwiftDate.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'SwiftDate' 3 | spec.version = '1.0.10' 4 | spec.summary = 'Swift (2.0+) library to easily manage NSDate objects. (Check 1.0.9 for Swift 1.2 Compatibility)' 5 | spec.homepage = 'https://github.com/malcommac/SwiftDate' 6 | spec.license = { :type => 'MIT', :file => 'LICENSE' } 7 | spec.author = { 'Daniele Margutti' => 'me@danielemargutti.com' } 8 | spec.social_media_url = 'http://twitter.com/danielemargutti' 9 | spec.source = { :git => 'https://github.com/malcommac/SwiftDate.git', :tag => "#{spec.version}" } 10 | spec.source_files = 'SwiftDate/*.swift' 11 | spec.ios.deployment_target = '8.0' 12 | spec.osx.deployment_target = '10.9' 13 | spec.requires_arc = true 14 | spec.module_name = 'SwiftDate' 15 | end 16 | -------------------------------------------------------------------------------- /SwiftDate/SwiftDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDate.swift 3 | // SwiftDate 4 | // 5 | // Copyright (c) 2015 Daniele Margutti 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | import Foundation 27 | 28 | //MARK: STRING EXTENSION SHORTCUTS 29 | 30 | public extension String { 31 | 32 | /** 33 | Create a new NSDate object with passed custom format string 34 | 35 | :param: format format as string 36 | 37 | :returns: a new NSDate instance with parsed date, or nil if it's fail 38 | */ 39 | func toDate(formatString formatString: String!) -> NSDate? { 40 | return NSDate.date(fromString: self, format: DateFormat.Custom(formatString)) 41 | } 42 | 43 | /** 44 | Create a new NSDate object with passed date format 45 | 46 | :param: format format 47 | 48 | :returns: a new NSDate instance with parsed date, or nil if it's fail 49 | */ 50 | func toDate(format format: DateFormat) -> NSDate? { 51 | return NSDate.date(fromString: self, format: format) 52 | } 53 | } 54 | 55 | //MARK: ACCESS TO DATE COMPONENTS 56 | 57 | public extension NSDate { 58 | 59 | // Use this as shortcuts for the most common formats for dates 60 | class var commonFormats : [String] { 61 | return [ 62 | "yyyy-MM-ddTHH:mm:ssZ", // ISO8601 63 | "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", 64 | "yyyy-MM-dd", 65 | "h:mm:ss A", 66 | "h:mm A", 67 | "MM/dd/yyyy", 68 | "MMMM d, yyyy", 69 | "MMMM d, yyyy LT", 70 | "dddd, MMMM D, yyyy LT", 71 | "yyyyyy-MM-dd", 72 | "yyyy-MM-dd", 73 | "GGGG-[W]WW-E", 74 | "GGGG-[W]WW", 75 | "yyyy-ddd", 76 | "HH:mm:ss.SSSS", 77 | "HH:mm:ss", 78 | "HH:mm", 79 | "HH" 80 | ] 81 | } 82 | 83 | /// Get the year component of the date 84 | var year : Int { return components.year } 85 | /// Get the month component of the date 86 | var month : Int { return components.month } 87 | // Get the week of the month component of the date 88 | var weekOfMonth: Int { return components.weekOfMonth } 89 | // Get the week of the month component of the date 90 | var weekOfYear: Int { return components.weekOfYear } 91 | /// Get the weekday component of the date 92 | var weekday: Int { return components.weekday } 93 | /// Get the weekday ordinal component of the date 94 | var weekdayOrdinal: Int { return components.weekdayOrdinal } 95 | /// Get the day component of the date 96 | var day: Int { return components.day } 97 | /// Get the hour component of the date 98 | var hour: Int { return components.hour } 99 | /// Get the minute component of the date 100 | var minute: Int { return components.minute } 101 | // Get the second component of the date 102 | var second: Int { return components.second } 103 | // Get the era component of the date 104 | var era: Int { return components.era } 105 | // Get the current month name based upon current locale 106 | var monthName: String { 107 | let dateFormatter = NSDate.localThreadDateFormatter() 108 | dateFormatter.locale = NSLocale.autoupdatingCurrentLocale() 109 | return dateFormatter.monthSymbols[month - 1] as String 110 | } 111 | // Get the current weekday name 112 | var weekdayName: String { 113 | let dateFormatter = NSDate.localThreadDateFormatter() 114 | dateFormatter.locale = NSLocale.autoupdatingCurrentLocale() 115 | dateFormatter.dateFormat = "EEEE" 116 | dateFormatter.timeZone = NSTimeZone.localTimeZone() 117 | return dateFormatter.stringFromDate(self) 118 | } 119 | 120 | 121 | private func firstWeekDate()-> (date : NSDate!, interval: NSTimeInterval) { 122 | // Sunday 1, Monday 2, Tuesday 3, Wednesday 4, Friday 5, Saturday 6 123 | let calendar = NSCalendar.currentCalendar() 124 | calendar.firstWeekday = NSCalendar.currentCalendar().firstWeekday 125 | var startWeek: NSDate? = nil 126 | var duration: NSTimeInterval = 0 127 | 128 | calendar.rangeOfUnit(NSCalendarUnit.WeekOfYear, startDate: &startWeek, interval: &duration, forDate: self) 129 | return (startWeek,duration) 130 | } 131 | 132 | /// Return the first day of the current date's week 133 | var firstDayOfWeek : Int { 134 | let (date,_) = self.firstWeekDate() 135 | return date.day 136 | } 137 | 138 | /// Return the last day of the week 139 | var lastDayOfWeek : Int { 140 | let (startWeek,interval) = self.firstWeekDate() 141 | let endWeek = startWeek?.dateByAddingTimeInterval(interval-1) 142 | return endWeek!.day 143 | } 144 | 145 | /// Return the nearest hour of the date 146 | var nearestHour:NSInteger{ 147 | let aTimeInterval = NSDate.timeIntervalSinceReferenceDate() + Double(D_MINUTE) * Double(30); 148 | 149 | let newDate = NSDate(timeIntervalSinceReferenceDate:aTimeInterval); 150 | let components = NSCalendar.currentCalendar().components(NSCalendarUnit.Hour, fromDate: newDate); 151 | return components.hour; 152 | } 153 | } 154 | 155 | //MARK: CREATE AND MANIPULATE DATE COMPONENTS 156 | 157 | public extension NSDate { 158 | 159 | /** 160 | Create a new NSDate instance from passed string with given format 161 | 162 | :param: string date as string 163 | :param: format parse formate. 164 | 165 | :returns: a new instance of the string 166 | */ 167 | class func date(fromString string: String, format: DateFormat) -> NSDate? { 168 | if string.isEmpty { 169 | return nil 170 | } 171 | 172 | let dateFormatter = NSDate.localThreadDateFormatter() 173 | switch format { 174 | case .ISO8601: // 1972-07-16T08:15:30-05:00 175 | dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 176 | dateFormatter.timeZone = NSTimeZone.localTimeZone() 177 | dateFormatter.dateFormat = ISO8601Formatter(fromString: string) 178 | return dateFormatter.dateFromString(string) 179 | case .AltRSS: // 09 Sep 2011 15:26:08 +0200 180 | var formattedString : NSString = string 181 | if formattedString.hasSuffix("Z") { 182 | formattedString = formattedString.substringToIndex(formattedString.length-1) + "GMT" 183 | } 184 | dateFormatter.dateFormat = "d MMM yyyy HH:mm:ss ZZZ" 185 | return dateFormatter.dateFromString(formattedString as String) 186 | case .RSS: // Fri, 09 Sep 2011 15:26:08 +0200 187 | var formattedString : NSString = string 188 | if formattedString.hasSuffix("Z") { 189 | formattedString = formattedString.substringToIndex(formattedString.length-1) + "GMT" 190 | } 191 | dateFormatter.dateFormat = "EEE, d MMM yyyy HH:mm:ss ZZZ" 192 | return dateFormatter.dateFromString(formattedString as String) 193 | case .Custom(let dateFormat): 194 | dateFormatter.dateFormat = dateFormat 195 | return dateFormatter.dateFromString(string) 196 | } 197 | } 198 | 199 | /** 200 | Attempts to handle all different ISO8601 formatters 201 | and returns correct date format for string 202 | http://www.w3.org/TR/NOTE-datetime 203 | */ 204 | class func ISO8601Formatter(fromString string: String) -> String { 205 | 206 | enum IS08601Format: Int { 207 | // YYYY (eg 1997) 208 | case Year = 4 209 | 210 | // YYYY-MM (eg 1997-07) 211 | case YearAndMonth = 7 212 | 213 | // YYYY-MM-DD (eg 1997-07-16) 214 | case CompleteDate = 10 215 | 216 | // YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) 217 | case CompleteDatePlusHoursAndMinutes = 22 218 | 219 | //YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) 220 | case CompleteDatePlusHoursMinutesAndSeconds = 25 221 | 222 | // YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) 223 | case CompleteDatePlusHoursMinutesSecondsAndDecimalFractionOfSecond = 28 224 | } 225 | 226 | var dateFormatter = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 227 | 228 | if let dateStringCount = IS08601Format(rawValue: string.characters.count) { 229 | switch dateStringCount { 230 | case .Year: 231 | dateFormatter = "yyyy" 232 | case .YearAndMonth: 233 | dateFormatter = "yyyy-MM" 234 | case .CompleteDate: 235 | dateFormatter = "yyyy-MM-dd" 236 | case .CompleteDatePlusHoursAndMinutes: 237 | dateFormatter = "yyyy-MM-dd'T'HH:mmZ" 238 | case .CompleteDatePlusHoursMinutesAndSeconds: 239 | dateFormatter = "yyyy-MM-dd'T'HH:mm:ssZ" 240 | default: 241 | // YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) 242 | dateFormatter = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 243 | } 244 | } 245 | return dateFormatter 246 | } 247 | 248 | /** 249 | Create a new NSDate instance based on refDate (if nil uses current date) and set components 250 | 251 | :param: refDate reference date instance (nil to use NSDate()) 252 | :param: year year component (nil to leave it untouched) 253 | :param: month month component (nil to leave it untouched) 254 | :param: day day component (nil to leave it untouched) 255 | :param: tz time zone component (it's the abbreviation of NSTimeZone, like 'UTC' or 'GMT+2', nil to use current time zone) 256 | 257 | :returns: a new NSDate with components changed according to passed params 258 | */ 259 | class func date(refDate refDate: NSDate?, year: Int?, month: Int?, day: Int?, tz: String?) -> NSDate { 260 | let referenceDate = refDate ?? NSDate() 261 | return referenceDate.set(year: year, month: month, day: day, hour: 0, minute: 0, second: 0, tz: tz) 262 | } 263 | 264 | /** 265 | Create a new NSDate instance based on refDate (if nil uses current date) and set components 266 | 267 | :param: refDate reference date instance (nil to use NSDate()) 268 | :param: year year component (nil to leave it untouched) 269 | :param: month month component (nil to leave it untouched) 270 | :param: day day component (nil to leave it untouched) 271 | :param: hour hour component (nil to leave it untouched) 272 | :param: minute minute component (nil to leave it untouched) 273 | :param: second second component (nil to leave it untouched) 274 | :param: tz time zone component (it's the abbreviation of NSTimeZone, like 'UTC' or 'GMT+2', nil to use current time zone) 275 | 276 | :returns: a new NSDate with components changed according to passed params 277 | */ 278 | class func date(refDate refDate: NSDate?, year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int, tz: String?) -> NSDate { 279 | let referenceDate = refDate ?? NSDate() 280 | return referenceDate.set(year: year, month: month, day: day, hour: hour, minute: minute, second: second, tz: tz) 281 | } 282 | 283 | /** 284 | Return a new NSDate instance with the current date and time set to 00:00:00 285 | 286 | :param: tz optional timezone abbreviation 287 | 288 | :returns: a new NSDate instance of the today's date 289 | */ 290 | class func today(tz: String? = nil) -> NSDate! { 291 | let nowDate = NSDate() 292 | return NSDate.date(refDate: nowDate, year: nowDate.year, month: nowDate.month, day: nowDate.day, tz: tz) 293 | } 294 | 295 | /** 296 | Return a new NSDate istance with the current date minus one day 297 | 298 | :param: tz optional timezone abbreviation 299 | 300 | :returns: a new NSDate instance which represent yesterday's date 301 | */ 302 | class func yesterday(tz: String? = nil) -> NSDate! { 303 | return today(tz)-1.day 304 | } 305 | 306 | /** 307 | Return a new NSDate istance with the current date plus one day 308 | 309 | :param: tz optional timezone abbreviation 310 | 311 | :returns: a new NSDate instance which represent tomorrow's date 312 | */ 313 | class func tomorrow(tz: String? = nil) -> NSDate! { 314 | return today(tz)+1.day 315 | } 316 | 317 | /** 318 | Individual set single component of the current date instance 319 | 320 | :param: year a non-nil value to change the year component of the instance 321 | :param: month a non-nil value to change the month component of the instance 322 | :param: day a non-nil value to change the day component of the instance 323 | :param: hour a non-nil value to change the hour component of the instance 324 | :param: minute a non-nil value to change the minute component of the instance 325 | :param: second a non-nil value to change the second component of the instance 326 | :param: tz a non-nil value (timezone abbreviation string as for NSTimeZone) to change the timezone component of the instance 327 | 328 | :returns: a new NSDate instance with changed values 329 | */ 330 | func set(year year: Int?, month: Int?, day: Int?, hour: Int?, minute: Int?, second: Int?, tz: String?) -> NSDate! { 331 | let components = self.components 332 | components.year = year ?? self.year 333 | components.month = month ?? self.month 334 | components.day = day ?? self.day 335 | components.hour = hour ?? self.hour 336 | components.minute = minute ?? self.minute 337 | components.second = second ?? self.second 338 | components.timeZone = (tz != nil ? NSTimeZone(abbreviation: tz!) : NSTimeZone.defaultTimeZone()) 339 | return NSCalendar.currentCalendar().dateFromComponents(components) 340 | } 341 | 342 | /** 343 | Allows you to set individual date components by passing an array of components name and associated values 344 | 345 | :param: componentsDict components dict. Accepted keys are year,month,day,hour,minute,second 346 | 347 | :returns: a new date instance with altered components according to passed dictionary 348 | */ 349 | func set(componentsDict componentsDict: [String:Int]!) -> NSDate? { 350 | if componentsDict.count == 0 { 351 | return self 352 | } 353 | let components = self.components 354 | for (thisComponent,value) in componentsDict { 355 | let unit : NSCalendarUnit = thisComponent._sdToCalendarUnit() 356 | components.setValue(value, forComponent: unit); 357 | } 358 | return NSCalendar.currentCalendar().dateFromComponents(components) 359 | } 360 | 361 | /** 362 | Allows you to set a single component by passing it's name (year,month,day,hour,minute,second are accepted). 363 | Please note: this method return a new immutable NSDate instance (NSDate are immutable, damn!). So while you 364 | can chain multiple set calls, if you need to alter more than one component see the method above which accept 365 | different params. 366 | 367 | :param: name the name of the component to alter (year,month,day,hour,minute,second are accepted) 368 | :param: value the value of the component 369 | 370 | :returns: a new date instance 371 | */ 372 | func set(name : String!, value : Int!) -> NSDate? { 373 | let unit : NSCalendarUnit = name._sdToCalendarUnit() 374 | if unit == [] { 375 | return nil 376 | } 377 | let components = self.components 378 | components.setValue(value, forComponent: unit); 379 | return NSCalendar.currentCalendar().dateFromComponents(components) 380 | } 381 | 382 | /** 383 | Add or subtract (via negative values) components from current date instance 384 | 385 | :param: years nil or +/- years to add or subtract from date 386 | :param: months nil or +/- months to add or subtract from date 387 | :param: weeks nil or +/- weeks to add or subtract from date 388 | :param: days nil or +/- days to add or subtract from date 389 | :param: hours nil or +/- hours to add or subtract from date 390 | :param: minutes nil or +/- minutes to add or subtract from date 391 | :param: seconds nil or +/- seconds to add or subtract from date 392 | 393 | :returns: a new NSDate instance with changed values 394 | */ 395 | func add(years years: Int?, months: Int?, weeks: Int?, days: Int?,hours: Int?,minutes: Int?,seconds: Int?) -> NSDate { 396 | let components = NSDateComponents() 397 | components.year = years ?? 0 398 | components.month = months ?? 0 399 | components.weekOfYear = weeks ?? 0 400 | components.day = days ?? 0 401 | components.hour = hours ?? 0 402 | components.minute = minutes ?? 0 403 | components.second = seconds ?? 0 404 | return self.addComponents(components) 405 | } 406 | 407 | /** 408 | Add/substract (based on sign) specified component with value 409 | 410 | :param: name component name (year,month,day,hour,minute,second) 411 | :param: value value of the component 412 | 413 | :returns: new date with altered component 414 | */ 415 | func add(name : String!, value : Int!) -> NSDate? { 416 | let unit : NSCalendarUnit = name._sdToCalendarUnit() 417 | if unit == [] { 418 | return nil 419 | } 420 | let components = NSDateComponents() 421 | components.setValue(value, forComponent: unit); 422 | return self.addComponents(components) 423 | } 424 | 425 | /** 426 | Add value specified by components in passed dictionary to the current date 427 | 428 | :param: componentsDict dictionary of the component to alter with value (year,month,day,hour,minute,second) 429 | 430 | :returns: new date with altered components 431 | */ 432 | func add(componentsDict componentsDict: [String:Int]!) -> NSDate? { 433 | if componentsDict.count == 0 { 434 | return self 435 | } 436 | let components = NSDateComponents() 437 | for (thisComponent,value) in componentsDict { 438 | let unit : NSCalendarUnit = thisComponent._sdToCalendarUnit() 439 | components.setValue(value, forComponent: unit); 440 | } 441 | return self.addComponents(components) 442 | } 443 | } 444 | 445 | //MARK: TIMEZONE UTILITIES 446 | 447 | public extension NSDate { 448 | /** 449 | Return a new NSDate in UTC format from the current system timezone 450 | 451 | :returns: a new NSDate instance 452 | */ 453 | func toUTC() -> NSDate { 454 | let tz : NSTimeZone = NSTimeZone.localTimeZone() 455 | let secs : Int = tz.secondsFromGMTForDate(self) 456 | return NSDate(timeInterval: NSTimeInterval(secs), sinceDate: self) 457 | } 458 | 459 | /** 460 | Convert an UTC NSDate instance to a local time NSDate (note: NSDate object does not contains info about the timezone!) 461 | 462 | :returns: a new NSDate instance 463 | */ 464 | func toLocalTime() -> NSDate { 465 | let tz : NSTimeZone = NSTimeZone.localTimeZone() 466 | let secs : Int = -tz.secondsFromGMTForDate(self) 467 | return NSDate(timeInterval: NSTimeInterval(secs), sinceDate: self) 468 | } 469 | 470 | /** 471 | Convert an UTC NSDate instance to passed timezone (note: NSDate object does not contains info about the timezone!) 472 | 473 | :param: abbreviation abbreviation of the time zone 474 | 475 | :returns: a new NSDate instance 476 | */ 477 | func toTimezone(abbreviation : String!) -> NSDate? { 478 | let tz : NSTimeZone? = NSTimeZone(abbreviation: abbreviation) 479 | if tz == nil { 480 | return nil 481 | } 482 | let secs : Int = tz!.secondsFromGMTForDate(self) 483 | return NSDate(timeInterval: NSTimeInterval(secs), sinceDate: self) 484 | } 485 | } 486 | 487 | //MARK: COMPARE DATES 488 | 489 | public extension NSDate { 490 | 491 | func secondsAfterDate(date: NSDate) -> Int { 492 | let interval = self.timeIntervalSinceDate(date) 493 | return Int(interval) 494 | } 495 | 496 | func secondsBeforeDate(date: NSDate) -> Int { 497 | let interval = date.timeIntervalSinceDate(self) 498 | return Int(interval) 499 | } 500 | 501 | /** 502 | Return the number of minutes between two dates. 503 | 504 | :param: date comparing date 505 | 506 | :returns: number of minutes 507 | */ 508 | func minutesAfterDate(date: NSDate) -> Int { 509 | let interval = self.timeIntervalSinceDate(date) 510 | return Int(interval / NSTimeInterval(D_MINUTE)) 511 | } 512 | 513 | func minutesBeforeDate(date: NSDate) -> Int { 514 | let interval = date.timeIntervalSinceDate(self) 515 | return Int(interval / NSTimeInterval(D_MINUTE)) 516 | } 517 | 518 | func hoursAfterDate(date: NSDate) -> Int { 519 | let interval = self.timeIntervalSinceDate(date) 520 | return Int(interval / NSTimeInterval(D_HOUR)) 521 | } 522 | 523 | func hoursBeforeDate(date: NSDate) -> Int { 524 | let interval = date.timeIntervalSinceDate(self) 525 | return Int(interval / NSTimeInterval(D_HOUR)) 526 | } 527 | 528 | func daysAfterDate(date: NSDate) -> Int { 529 | let interval = self.timeIntervalSinceDate(date) 530 | return Int(interval / NSTimeInterval(D_DAY)) 531 | } 532 | 533 | func daysBeforeDate(date: NSDate) -> Int { 534 | let interval = date.timeIntervalSinceDate(self) 535 | return Int(interval / NSTimeInterval(D_DAY)) 536 | } 537 | 538 | /** 539 | Compare two dates and return true if they are equals 540 | 541 | :param: date date to compare with 542 | :param: ignoreTime true to ignore time of the date 543 | 544 | :returns: true if two dates are equals 545 | */ 546 | func isEqualToDate(date: NSDate, ignoreTime: Bool) -> Bool { 547 | if ignoreTime { 548 | let comp1 = NSDate.components(fromDate: self) 549 | let comp2 = NSDate.components(fromDate: date) 550 | return ((comp1.year == comp2.year) && (comp1.month == comp2.month) && (comp1.day == comp2.day)) 551 | } else { 552 | return self.isEqualToDate(date) 553 | } 554 | } 555 | 556 | /** 557 | Return true if given date's time in passed range 558 | 559 | :param: minTime min time interval (by default format is "HH:mm", but you can specify your own format in format parameter) 560 | :param: maxTime max time interval (by default format is "HH:mm", but you can specify your own format in format parameter) 561 | :param: format nil or a valid format string used to parse minTime and maxTime from their string representation (when nil HH:mm is used) 562 | 563 | :returns: true if date's time component falls into given range 564 | */ 565 | func isInTimeRange(minTime: String!, maxTime: String!, format: String?) -> Bool { 566 | let dateFormatter = NSDate.localThreadDateFormatter() 567 | dateFormatter.dateFormat = format ?? "HH:mm" 568 | dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC") 569 | let minTimeDate = dateFormatter.dateFromString(minTime) 570 | let maxTimeDate = dateFormatter.dateFromString(maxTime) 571 | if minTimeDate == nil || maxTimeDate == nil { 572 | return false 573 | } 574 | let inBetween = (self.compare(minTimeDate!) == NSComparisonResult.OrderedDescending && 575 | self.compare(maxTimeDate!) == NSComparisonResult.OrderedAscending) 576 | return inBetween 577 | } 578 | 579 | /** 580 | Return true if the date's year is a leap year 581 | 582 | :returns: true if date's year is a leap year 583 | */ 584 | func isLeapYear() -> Bool { 585 | let year = self.year 586 | return year % 400 == 0 ? true : ((year % 4 == 0) && (year % 100 != 0)) 587 | } 588 | 589 | /** 590 | Return the number of days in current date's month 591 | 592 | :returns: number of days of the month 593 | */ 594 | func monthDays () -> Int { 595 | return NSCalendar.currentCalendar().rangeOfUnit(NSCalendarUnit.Day, inUnit: NSCalendarUnit.Month, forDate: self).length 596 | } 597 | 598 | /** 599 | True if the date is the current date 600 | 601 | :returns: true if date is today 602 | */ 603 | func isToday() -> Bool { 604 | return self.isEqualToDate(NSDate(), ignoreTime: true) 605 | } 606 | 607 | /** 608 | True if the date is the current date plus one day (tomorrow) 609 | 610 | :returns: true if date is tomorrow 611 | */ 612 | func isTomorrow() -> Bool { 613 | return self.isEqualToDate(NSDate()+1.day, ignoreTime:true) 614 | } 615 | 616 | /** 617 | True if the date is the current date minus one day (yesterday) 618 | 619 | :returns: true if date is yesterday 620 | */ 621 | func isYesterday() -> Bool { 622 | return self.isEqualToDate(NSDate()-1.day, ignoreTime:true) 623 | } 624 | 625 | /** 626 | Return true if the date falls into the current week 627 | 628 | :returns: true if date is inside the current week days range 629 | */ 630 | func isThisWeek() -> Bool { 631 | return self.isSameWeekOf(NSDate()) 632 | } 633 | 634 | /** 635 | Return true if the date is in the same week of passed date 636 | 637 | :param: date date to compare with 638 | 639 | :returns: true if both dates falls in the same week 640 | */ 641 | func isSameWeekOf(date: NSDate) -> Bool { 642 | let comp1 = NSDate.components(fromDate: self) 643 | let comp2 = NSDate.components(fromDate: date) 644 | // Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week 645 | if comp1.weekOfYear != comp2.weekOfYear { 646 | return false 647 | } 648 | // Must have a time interval under 1 week 649 | let weekInSeconds = NSTimeInterval(D_WEEK) 650 | return abs(self.timeIntervalSinceDate(date)) < weekInSeconds 651 | } 652 | 653 | /** 654 | Return the first day of the passed date's week (Sunday) 655 | 656 | :returns: NSDate with the date of the first day of the week 657 | */ 658 | func dateAtWeekStart() -> NSDate { 659 | let flags : NSCalendarUnit = [NSCalendarUnit.Year,NSCalendarUnit.Month , 660 | NSCalendarUnit.WeekOfYear, 661 | NSCalendarUnit.Weekday] 662 | let components = NSCalendar.currentCalendar().components(flags, fromDate: self) 663 | components.weekday = 1 // Sunday 664 | components.hour = 0 665 | components.minute = 0 666 | components.second = 0 667 | return NSCalendar.currentCalendar().dateFromComponents(components)! 668 | } 669 | 670 | /// Return a date which represent the beginning of the current day (at 00:00:00) 671 | var beginningOfDay: NSDate { 672 | return set(year: nil, month: nil, day: nil, hour: 0, minute: 0, second: 0, tz: nil) 673 | } 674 | 675 | /// Return a date which represent the end of the current day (at 23:59:59) 676 | var endOfDay: NSDate { 677 | return set(year: nil, month: nil, day: nil, hour: 23, minute: 59, second: 59, tz: nil) 678 | } 679 | 680 | /// Return the first day of the month of the current date 681 | var beginningOfMonth: NSDate { 682 | return set(year: nil, month: nil, day: 1, hour: 0, minute: 0, second: 0, tz: nil) 683 | } 684 | 685 | /// Return the last day of the month of the current date 686 | var endOfMonth: NSDate { 687 | let lastDay = NSCalendar.currentCalendar().rangeOfUnit(.Day, inUnit: .Month, forDate: self).length 688 | return set(year: nil, month: nil, day: lastDay, hour: 23, minute: 59, second: 59, tz: nil) 689 | } 690 | 691 | /// Return the first day of the year of the current date 692 | var beginningOfYear: NSDate { 693 | return set(year: nil, month: 1, day: 1, hour: 0, minute: 0, second: 0, tz: nil) 694 | } 695 | 696 | /// Return the last day of the year of the current date 697 | var endOfYear: NSDate { 698 | return set(year: nil, month: 12, day: 31, hour: 23, minute: 59, second: 59, tz: nil) 699 | } 700 | 701 | /** 702 | Return true if current date's day is not a weekend day 703 | 704 | :returns: true if date's day is a week day, not a weekend day 705 | */ 706 | func isWeekday() -> Bool { 707 | return !self.isWeekend() 708 | } 709 | 710 | /** 711 | Return true if the date is the weekend 712 | 713 | :returns: true or false 714 | */ 715 | func isWeekend() -> Bool { 716 | let range = NSCalendar.currentCalendar().maximumRangeOfUnit(NSCalendarUnit.Weekday) 717 | return (self.weekday == range.location || self.weekday == range.length) 718 | } 719 | 720 | } 721 | 722 | //MARK: CONVERTING DATE TO STRING 723 | 724 | public extension NSDate { 725 | 726 | /** 727 | Return a formatted string with passed style for date and time 728 | 729 | :param: dateStyle style of the date component into the output string 730 | :param: timeStyle style of the time component into the output string 731 | :param: relativeDate true to use relative date style 732 | 733 | :returns: string representation of the date 734 | */ 735 | public func toString(dateStyle dateStyle: NSDateFormatterStyle, timeStyle: NSDateFormatterStyle, relativeDate: Bool = false) -> String { 736 | let dateFormatter = NSDate.localThreadDateFormatter() 737 | dateFormatter.dateStyle = dateStyle 738 | dateFormatter.timeStyle = timeStyle 739 | dateFormatter.doesRelativeDateFormatting = relativeDate 740 | return dateFormatter.stringFromDate(self) 741 | } 742 | 743 | /** 744 | Return a new string which represent the NSDate into passed format 745 | 746 | :param: format format of the output string. Choose one of the available format or use a custom string 747 | 748 | :returns: a string with formatted date 749 | */ 750 | public func toString(format format: DateFormat) -> String { 751 | var dateFormat: String 752 | switch format { 753 | case .ISO8601: 754 | dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" 755 | case .RSS: 756 | dateFormat = "EEE, d MMM yyyy HH:mm:ss ZZZ" 757 | case .AltRSS: 758 | dateFormat = "d MMM yyyy HH:mm:ss ZZZ" 759 | case .Custom(let string): 760 | dateFormat = string 761 | } 762 | let dateFormatter = NSDate.localThreadDateFormatter() 763 | dateFormatter.dateFormat = dateFormat 764 | return dateFormatter.stringFromDate(self) 765 | } 766 | 767 | /** 768 | Return an ISO8601 formatted string from the current date instance 769 | 770 | :returns: string with date in ISO8601 format 771 | */ 772 | public func toISOString() -> String { 773 | let dateFormatter = NSDate.localThreadDateFormatter() 774 | dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 775 | dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC") 776 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS" 777 | return dateFormatter.stringFromDate(self).stringByAppendingString("Z") 778 | } 779 | 780 | /** 781 | Return a relative string which represent the date instance 782 | 783 | :param: fromDate comparison date (by default is the current NSDate()) 784 | :param: abbreviated true to use abbreviated unit forms (ie. "ys" instead of "years") 785 | :param: maxUnits max detail units to print (ie. "1 hour 47 minutes" is maxUnit=2, "1 hour" is maxUnit=1) 786 | 787 | :returns: formatted string 788 | */ 789 | public func toRelativeString(fromDate: NSDate = NSDate(), abbreviated : Bool = false, maxUnits: Int = 1) -> String { 790 | let seconds = fromDate.timeIntervalSinceDate(self) 791 | if fabs(seconds) < 1 { 792 | return "just now"._sdLocalize 793 | } 794 | 795 | let significantFlags : NSCalendarUnit = NSDate.componentFlags() 796 | let components = NSCalendar.currentCalendar().components(significantFlags, fromDate: fromDate, toDate: self, options: []) 797 | 798 | var string = String() 799 | var isApproximate:Bool = false 800 | var numberOfUnits:Int = 0 801 | let unitList : [String] = ["year", "month", "weekOfYear", "day", "hour", "minute", "second"] 802 | for unitName in unitList { 803 | let unit : NSCalendarUnit = unitName._sdToCalendarUnit() 804 | if ((significantFlags.rawValue & unit.rawValue) != 0) && 805 | (_sdCompareCalendarUnit(NSCalendarUnit.Second, other: unit) != .OrderedDescending) { 806 | let number:NSNumber = NSNumber(float: fabsf(components.valueForKey(unitName)!.floatValue)) 807 | if Bool(number.integerValue) { 808 | let singular = (number.unsignedIntegerValue == 1) 809 | let suffix = String(format: "%@ %@", arguments: [number, _sdLocalizeStringForValue(singular, unit: unit, abbreviated: abbreviated)]) 810 | if string.isEmpty { 811 | string = suffix 812 | } else if numberOfUnits < maxUnits { 813 | string += String(format: " %@", arguments: [suffix]) 814 | } else { 815 | isApproximate = true 816 | } 817 | numberOfUnits += 1 818 | } 819 | } 820 | } 821 | 822 | if string.isEmpty == false { 823 | if seconds > 0 { 824 | string = String(format: "%@ %@", arguments: [string, "ago"._sdLocalize]) 825 | } else { 826 | string = String(format: "%@ %@", arguments: [string, "from now"._sdLocalize]) 827 | } 828 | 829 | if (isApproximate) { 830 | string = String(format: "about %@", arguments: [string]) 831 | } 832 | } 833 | return string 834 | } 835 | 836 | /** 837 | Return a string representation of the date where both date and time are in short style format 838 | 839 | :returns: date's string representation 840 | */ 841 | public func toShortString() -> String { 842 | return toString(dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.ShortStyle) 843 | } 844 | 845 | /** 846 | Return a string representation of the date where both date and time are in medium style format 847 | 848 | :returns: date's string representation 849 | */ 850 | public func toMediumString() -> String { 851 | return toString(dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.MediumStyle) 852 | } 853 | 854 | /** 855 | Return a string representation of the date where both date and time are in long style format 856 | 857 | :returns: date's string representation 858 | */ 859 | public func toLongString() -> String { 860 | return toString(dateStyle: NSDateFormatterStyle.LongStyle, timeStyle: NSDateFormatterStyle.LongStyle) 861 | } 862 | 863 | /** 864 | Return a string representation of the date with only the date in short style format (no time) 865 | 866 | :returns: date's string representation 867 | */ 868 | public func toShortDateString() -> String { 869 | return toString(dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.NoStyle) 870 | } 871 | 872 | /** 873 | Return a string representation of the date with only the time in short style format (no date) 874 | 875 | :returns: date's string representation 876 | */ 877 | public func toShortTimeString() -> String { 878 | return toString(dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.ShortStyle) 879 | } 880 | 881 | /** 882 | Return a string representation of the date with only the date in medium style format (no date) 883 | 884 | :returns: date's string representation 885 | */ 886 | public func toMediumDateString() -> String { 887 | return toString(dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.NoStyle) 888 | } 889 | 890 | /** 891 | Return a string representation of the date with only the time in medium style format (no date) 892 | 893 | :returns: date's string representation 894 | */ 895 | public func toMediumTimeString() -> String { 896 | return toString(dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.MediumStyle) 897 | } 898 | 899 | /** 900 | Return a string representation of the date with only the date in long style format (no date) 901 | 902 | :returns: date's string representation 903 | */ 904 | public func toLongDateString() -> String { 905 | return toString(dateStyle: NSDateFormatterStyle.LongStyle, timeStyle: NSDateFormatterStyle.NoStyle) 906 | } 907 | 908 | /** 909 | Return a string representation of the date with only the time in long style format (no date) 910 | 911 | :returns: date's string representation 912 | */ 913 | public func toLongTimeString() -> String { 914 | return toString(dateStyle: NSDateFormatterStyle.NoStyle, timeStyle: NSDateFormatterStyle.LongStyle) 915 | } 916 | 917 | } 918 | 919 | //MARK: PRIVATE ACCESSORY METHODS 920 | 921 | private extension NSDate { 922 | 923 | private class func components(fromDate fromDate: NSDate) -> NSDateComponents! { 924 | return NSCalendar.currentCalendar().components(NSDate.componentFlags(), fromDate: fromDate) 925 | } 926 | 927 | private func addComponents(components: NSDateComponents) -> NSDate { 928 | let cal = NSCalendar.currentCalendar() 929 | return cal.dateByAddingComponents(components, toDate: self, options: [])! 930 | } 931 | 932 | private class func componentFlags() -> NSCalendarUnit { 933 | return [NSCalendarUnit.Year , 934 | NSCalendarUnit.Month , 935 | NSCalendarUnit.Day, 936 | NSCalendarUnit.WeekOfYear, 937 | NSCalendarUnit.Hour , 938 | NSCalendarUnit.Minute , 939 | NSCalendarUnit.Second , 940 | NSCalendarUnit.Weekday , 941 | NSCalendarUnit.WeekdayOrdinal, 942 | NSCalendarUnit.WeekOfYear] 943 | } 944 | 945 | /// Return the NSDateComponents which represent current date 946 | private var components: NSDateComponents { 947 | return NSCalendar.currentCalendar().components(NSDate.componentFlags(), fromDate: self) 948 | } 949 | 950 | /** 951 | This function uses NSThread dictionary to store and retrive a thread-local object, creating it if it has not already been created 952 | 953 | :param: key identifier of the object context 954 | :param: create create closure that will be invoked to create the object 955 | 956 | :returns: a cached instance of the object 957 | */ 958 | private class func cachedObjectInCurrentThread(key: String, create: () -> T) -> T { 959 | if let threadDictionary = NSThread.currentThread().threadDictionary as NSMutableDictionary? { 960 | if let cachedObject = threadDictionary[key] as! T? { 961 | return cachedObject 962 | } else { 963 | let newObject = create() 964 | threadDictionary[key] = newObject 965 | return newObject 966 | } 967 | } else { 968 | assert(false, "Current NSThread dictionary is nil. This should never happens, we will return a new instance of the object on each call") 969 | return create() 970 | } 971 | } 972 | 973 | /** 974 | Return a thread-cached NSDateFormatter instance 975 | 976 | :returns: instance of NSDateFormatter 977 | */ 978 | private class func localThreadDateFormatter() -> NSDateFormatter { 979 | return NSDate.cachedObjectInCurrentThread("com.library.swiftdate.dateformatter") { 980 | let dateFormatter = NSDateFormatter() 981 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" 982 | return dateFormatter 983 | } 984 | } 985 | } 986 | 987 | //MARK: RELATIVE NSDATE CONVERSION PRIVATE METHODS 988 | 989 | private extension NSDate { 990 | func _sdCompareCalendarUnit(unit:NSCalendarUnit, other:NSCalendarUnit) -> NSComparisonResult { 991 | let nUnit = _sdNormalizedCalendarUnit(unit) 992 | let nOther = _sdNormalizedCalendarUnit(other) 993 | 994 | if (nUnit == NSCalendarUnit.WeekOfYear) != (nOther == NSCalendarUnit.WeekOfYear) { 995 | if nUnit == NSCalendarUnit.WeekOfYear { 996 | switch nUnit { 997 | case NSCalendarUnit.Year, NSCalendarUnit.Month: 998 | return .OrderedAscending 999 | default: 1000 | return .OrderedDescending 1001 | } 1002 | } else { 1003 | switch nOther { 1004 | case NSCalendarUnit.Year, NSCalendarUnit.Month: 1005 | return .OrderedDescending 1006 | default: 1007 | return .OrderedAscending 1008 | } 1009 | } 1010 | } else { 1011 | if nUnit.rawValue > nOther.rawValue { 1012 | return .OrderedAscending 1013 | } else if (nUnit.rawValue < nOther.rawValue) { 1014 | return .OrderedDescending 1015 | } else { 1016 | return .OrderedSame 1017 | } 1018 | } 1019 | } 1020 | 1021 | private func _sdNormalizedCalendarUnit(unit:NSCalendarUnit) -> NSCalendarUnit { 1022 | switch unit { 1023 | case NSCalendarUnit.WeekOfMonth, NSCalendarUnit.WeekOfYear: 1024 | return NSCalendarUnit.WeekOfYear 1025 | case NSCalendarUnit.Weekday, NSCalendarUnit.WeekdayOrdinal: 1026 | return NSCalendarUnit.Day 1027 | default: 1028 | return unit; 1029 | } 1030 | } 1031 | 1032 | 1033 | func _sdLocalizeStringForValue(singular : Bool, unit: NSCalendarUnit, abbreviated: Bool = false) -> String { 1034 | var toTranslate : String = "" 1035 | switch unit { 1036 | 1037 | case NSCalendarUnit.Year where singular: toTranslate = (abbreviated ? "yr" : "year") 1038 | case NSCalendarUnit.Year where !singular: toTranslate = (abbreviated ? "yrs" : "years") 1039 | 1040 | case NSCalendarUnit.Month where singular: toTranslate = (abbreviated ? "mo" : "month") 1041 | case NSCalendarUnit.Month where !singular: toTranslate = (abbreviated ? "mos" : "months") 1042 | 1043 | case NSCalendarUnit.WeekOfYear where singular: toTranslate = (abbreviated ? "wk" : "week") 1044 | case NSCalendarUnit.WeekOfYear where !singular: toTranslate = (abbreviated ? "wks" : "weeks") 1045 | 1046 | case NSCalendarUnit.Day where singular: toTranslate = "day" 1047 | case NSCalendarUnit.Day where !singular: toTranslate = "days" 1048 | 1049 | case NSCalendarUnit.Hour where singular: toTranslate = (abbreviated ? "hr" : "hour") 1050 | case NSCalendarUnit.Hour where !singular: toTranslate = (abbreviated ? "hrs" : "hours") 1051 | 1052 | case NSCalendarUnit.Minute where singular: toTranslate = (abbreviated ? "min" : "minute") 1053 | case NSCalendarUnit.Minute where !singular: toTranslate = (abbreviated ? "mins" : "minutes") 1054 | 1055 | case NSCalendarUnit.Second where singular: toTranslate = (abbreviated ? "s" : "second") 1056 | case NSCalendarUnit.Second where !singular: toTranslate = (abbreviated ? "s" : "seconds") 1057 | 1058 | default: toTranslate = "" 1059 | } 1060 | return toTranslate._sdLocalize 1061 | } 1062 | 1063 | func localizedSimpleStringForComponents(components:NSDateComponents) -> String { 1064 | if (components.year == -1) { 1065 | return "last year"._sdLocalize 1066 | } else if (components.month == -1 && components.year == 0) { 1067 | return "last month"._sdLocalize 1068 | } else if (components.weekOfYear == -1 && components.year == 0 && components.month == 0) { 1069 | return "last week"._sdLocalize 1070 | } else if (components.day == -1 && components.year == 0 && components.month == 0 && components.weekOfYear == 0) { 1071 | return "yesterday"._sdLocalize 1072 | } else if (components == 1) { 1073 | return "next year"._sdLocalize 1074 | } else if (components.month == 1 && components.year == 0) { 1075 | return "next month"._sdLocalize 1076 | } else if (components.weekOfYear == 1 && components.year == 0 && components.month == 0) { 1077 | return "next week"._sdLocalize 1078 | } else if (components.day == 1 && components.year == 0 && components.month == 0 && components.weekOfYear == 0) { 1079 | return "tomorrow"._sdLocalize 1080 | } 1081 | return "" 1082 | } 1083 | } 1084 | 1085 | //MARK: OPERATIONS WITH DATES (==,!=,<,>,<=,>=) 1086 | 1087 | extension NSDate : Comparable {} 1088 | 1089 | public func == (left: NSDate, right: NSDate) -> Bool { 1090 | return (left.compare(right) == NSComparisonResult.OrderedSame) 1091 | } 1092 | 1093 | public func != (left: NSDate, right: NSDate) -> Bool { 1094 | return !(left == right) 1095 | } 1096 | 1097 | public func < (left: NSDate, right: NSDate) -> Bool { 1098 | return (left.compare(right) == NSComparisonResult.OrderedAscending) 1099 | } 1100 | 1101 | public func > (left: NSDate, right: NSDate) -> Bool { 1102 | return (left.compare(right) == NSComparisonResult.OrderedDescending) 1103 | } 1104 | 1105 | public func <= (left: NSDate, right: NSDate) -> Bool { 1106 | return !(left > right) 1107 | } 1108 | 1109 | public func >= (left: NSDate, right: NSDate) -> Bool { 1110 | return !(left < right) 1111 | } 1112 | 1113 | //MARK: ARITHMETIC OPERATIONS WITH DATES (-,-=,+,+=) 1114 | 1115 | public func - (left : NSDate, right: NSTimeInterval) -> NSDate { 1116 | return left.dateByAddingTimeInterval(-right) 1117 | } 1118 | 1119 | public func -= (inout left: NSDate, right: NSTimeInterval) { 1120 | left = left.dateByAddingTimeInterval(-right) 1121 | } 1122 | 1123 | public func + (left: NSDate, right: NSTimeInterval) -> NSDate { 1124 | return left.dateByAddingTimeInterval(right) 1125 | } 1126 | 1127 | public func += (inout left: NSDate, right: NSTimeInterval) { 1128 | left = left.dateByAddingTimeInterval(right) 1129 | } 1130 | 1131 | public func - (left: NSDate, right: CalendarType) -> NSDate { 1132 | let calendarType = right.copy() 1133 | calendarType.amount = -calendarType.amount 1134 | let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 1135 | let dateComponents = calendarType.dateComponents() 1136 | let finalDate = calendar.dateByAddingComponents(dateComponents, toDate: left, options: [])! 1137 | return finalDate 1138 | } 1139 | 1140 | public func -= (inout left: NSDate, right: CalendarType) { 1141 | left = left - right 1142 | } 1143 | 1144 | public func + (left: NSDate, right: CalendarType) -> NSDate { 1145 | let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 1146 | return calendar.dateByAddingComponents(right.dateComponents(), toDate: left, options: [])! 1147 | } 1148 | 1149 | public func += (inout left: NSDate, right: CalendarType) { 1150 | left = left + right 1151 | } 1152 | 1153 | //MARK: SUPPORTING STRUCTURES 1154 | 1155 | public class CalendarType { 1156 | var calendarUnit : NSCalendarUnit 1157 | var amount : Int 1158 | 1159 | init(amount : Int) { 1160 | self.calendarUnit = [] 1161 | self.amount = amount 1162 | } 1163 | 1164 | init(amount: Int, calendarUnit: NSCalendarUnit) { 1165 | self.calendarUnit = calendarUnit 1166 | self.amount = amount 1167 | } 1168 | 1169 | func dateComponents() -> NSDateComponents { 1170 | return NSDateComponents() 1171 | } 1172 | 1173 | func copy() -> CalendarType { 1174 | return CalendarType(amount: self.amount, calendarUnit: self.calendarUnit) 1175 | } 1176 | } 1177 | 1178 | public class MonthCalendarType : CalendarType { 1179 | 1180 | override init(amount : Int) { 1181 | super.init(amount: amount) 1182 | self.calendarUnit = NSCalendarUnit.Month 1183 | } 1184 | 1185 | override func dateComponents() -> NSDateComponents { 1186 | let components = super.dateComponents() 1187 | components.month = self.amount 1188 | return components 1189 | } 1190 | 1191 | override func copy() -> MonthCalendarType { 1192 | let objCopy = MonthCalendarType(amount: self.amount) 1193 | objCopy.calendarUnit = self.calendarUnit 1194 | return objCopy; 1195 | } 1196 | } 1197 | 1198 | public class YearCalendarType : CalendarType { 1199 | 1200 | override init(amount : Int) { 1201 | super.init(amount: amount, calendarUnit: NSCalendarUnit.Year) 1202 | } 1203 | 1204 | override func dateComponents() -> NSDateComponents { 1205 | let components = super.dateComponents() 1206 | components.year = self.amount 1207 | return components 1208 | } 1209 | 1210 | override func copy() -> YearCalendarType { 1211 | let objCopy = YearCalendarType(amount: self.amount) 1212 | objCopy.calendarUnit = self.calendarUnit 1213 | return objCopy 1214 | } 1215 | } 1216 | 1217 | public extension Int { 1218 | var seconds : NSTimeInterval { 1219 | return NSTimeInterval(self) 1220 | } 1221 | var second : NSTimeInterval { 1222 | return (self.seconds) 1223 | } 1224 | var minutes : NSTimeInterval { 1225 | return (self.seconds*60) 1226 | } 1227 | var minute : NSTimeInterval { 1228 | return self.minutes 1229 | } 1230 | var hours : NSTimeInterval { 1231 | return (self.minutes*60) 1232 | } 1233 | var hour : NSTimeInterval { 1234 | return self.hours 1235 | } 1236 | var days : NSTimeInterval { 1237 | return (self.hours*24) 1238 | } 1239 | var day : NSTimeInterval { 1240 | return self.days 1241 | } 1242 | var weeks : NSTimeInterval { 1243 | return (self.days*7) 1244 | } 1245 | var week : NSTimeInterval { 1246 | return self.weeks 1247 | } 1248 | var workWeeks : NSTimeInterval { 1249 | return (self.days*5) 1250 | } 1251 | var workWeek : NSTimeInterval { 1252 | return self.workWeeks 1253 | } 1254 | var months : MonthCalendarType { 1255 | return MonthCalendarType(amount: self) 1256 | } 1257 | var month : MonthCalendarType { 1258 | return self.months 1259 | } 1260 | var years : YearCalendarType { 1261 | return YearCalendarType(amount: self) 1262 | } 1263 | var year : YearCalendarType { 1264 | return self.years 1265 | } 1266 | } 1267 | 1268 | //MARK: PRIVATE STRING EXTENSION 1269 | 1270 | private extension String { 1271 | 1272 | var _sdLocalize: String { 1273 | return NSBundle.mainBundle().localizedStringForKey(self, value: nil, table: "SwiftDates") 1274 | } 1275 | 1276 | func _sdToCalendarUnit() -> NSCalendarUnit { 1277 | switch self { 1278 | case "year": 1279 | return NSCalendarUnit.Year 1280 | case "month": 1281 | return NSCalendarUnit.Month 1282 | case "weekOfYear": 1283 | return NSCalendarUnit.WeekOfYear 1284 | case "day": 1285 | return NSCalendarUnit.Day 1286 | case "hour": 1287 | return NSCalendarUnit.Hour 1288 | case "minute": 1289 | return NSCalendarUnit.Minute 1290 | case "second": 1291 | return NSCalendarUnit.Second 1292 | default: 1293 | return [] 1294 | } 1295 | } 1296 | } 1297 | 1298 | public enum DateFormat { 1299 | case ISO8601, RSS, AltRSS 1300 | case Custom(String) 1301 | } 1302 | 1303 | let D_SECOND = 1 1304 | let D_MINUTE = 60 1305 | let D_HOUR = 3600 1306 | let D_DAY = 86400 1307 | let D_WEEK = 604800 1308 | let D_YEAR = 31556926 1309 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyangcun/SwiftDate/6187efcca84f03c99ac72a5bebe3bae315244dad/assets/logo.png --------------------------------------------------------------------------------