I have a date stored on my online server database which is in GMT. I load the date and convert it to the user's timezone using the following code :
if let messagedate = oneitem["timestamp"] as? String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = dateFormatter.dateFromString(messagedate)
let source_timezone = NSTimeZone(abbreviation: "GMT")
let local_timezone = NSTimeZone.systemTimeZone()
let source_EDT_offset = source_timezone?.secondsFromGMTForDate(date!)
let destination_EDT_offset = local_timezone.secondsFromGMTForDate(date!)
let time_interval : NSTimeInterval = Double(destination_EDT_offset - source_EDT_offset!)
let final_date = NSDate(timeInterval: time_interval, sinceDate: date!)
curr_item.date = final_date
}
Now I need to convert the date back to GMT in order to communicate it to the server, however I'm not sure how to convert it back to GMT.
Simpler version:
extension Date {
func convertToTimeZone(initTimeZone: TimeZone, timeZone: TimeZone) -> Date {
let delta = TimeInterval(timeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}
}
Couldn't you just use your data formatter again with a different time zone and convert it? Such as
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
let gmtDate = dateFormatter.dateFromString(string: "your old date as string here")
At time of writing, most answers contain an edge case bug near DST switchover times (see my note about other answers below). If you just want to convert a date string with no time offset to a Date in a particular time zone, Amloelxer's answer is best, but for the benefit of those with the question of "how to convert a Date between timezones", there are two cases:
Case 1:
Convert a Date to another time zone while preserving the day and time from the initial time zone.
E.g. for GMT to EST: 2020-03-08T10:00:00Z to 2020-03-08T10:00:00-04:00
Case 2:
Convert a Date to the day and time from another time zone while preserving the initial time zone.
E.g. for EST to GMT: 2020-03-08T06:00:00-04:00 to 2020-03-08T10:00:00-04:00 (because the initial Date is 10am in GMT)
These two cases are actually the same (the example start and end Dates are identical), except they are worded differently to swap which time zone is the "initial" and which is the "target". The two solutions below are therefore equivalent if you swap the time zones between them, so you can choose the one that conceptually fits your use case better.
extension Calendar {
// case 1
func dateBySetting(timeZone: TimeZone, of date: Date) -> Date? {
var components = dateComponents(in: self.timeZone, from: date)
components.timeZone = timeZone
return self.date(from: components)
}
// case 2
func dateBySettingTimeFrom(timeZone: TimeZone, of date: Date) -> Date? {
var components = dateComponents(in: timeZone, from: date)
components.timeZone = self.timeZone
return self.date(from: components)
}
}
// example values
let initTz = TimeZone(abbreviation: "GMT")!
let targetTz = TimeZone(abbreviation: "EST")!
let initDate = Calendar.current.date(from: .init(timeZone: initTz, year: 2020, month: 3, day: 8, hour: 4))!
// usage
var calendar = Calendar.current
calendar.timeZone = initTz
let case1TargetDate = calendar.dateBySetting(timeZone: targetTz, of: initDate)!
let case2TargetDate = calendar.dateBySettingTimeFrom(timeZone: targetTz, of: initDate)!
// print results
let formatter = ISO8601DateFormatter()
formatter.timeZone = targetTz // case 1 is concerned with what the `Date` looks like in the target time zone
print(formatter.string(from: case1TargetDate)) // 2020-03-08T04:00:00-04:00
// for case 2, find the initial `Date`'s time in the target time zone
print(formatter.string(from: initDate)) // 2020-03-07T23:00:00-05:00 (the target date should have this same time)
formatter.timeZone = initTz // case 2 is concerned with what the `Date` looks like in the initial time zone
print(formatter.string(from: case2TargetDate)) // 2020-03-07T23:00:00Z
A note about other answers
At time of writing, most other answers assume one of the two above cases, but more importantly, they share a bug - they attempt to calculate the time difference between the time zones, where the sign of the difference determines the case:
Case 1:
initialTz.secondsFromGMT(for: initialDate) - targetTz.secondsFromGMT(for: initialDate)
Case 2:
targetTz.secondsFromGMT(for: initialDate) - initialTz.secondsFromGMT(for: initialDate)
secondsFromGMT takes the Date for which you want to know the offset, so in both cases the target offset should really be targetTz.secondsFromGMT(for: targetDate), which is a catch-22, since we don't know the target date yet. However, in most cases where the Dates are close, as they are here, targetTz.secondsFromGMT(for: initialDate) and targetTz.secondsFromGMT(for: targetDate) are equal - a bug only occurs when they differ, which happens when the time offset changes between the two Dates in the target time zone, e.g. for DST. Here is a bugged example for each case:
extension Date {
// case 1 (bugged)
func converting(from initTz: TimeZone, to targetTz: TimeZone) -> Date {
return self + Double(initTz.secondsFromGMT(for: self) - targetTz.secondsFromGMT(for: self))
}
// case 2 (bugged)
func convertingTime(from initTz: TimeZone, to targetTz: TimeZone) -> Date {
return self + Double(targetTz.secondsFromGMT(for: self) - initTz.secondsFromGMT(for: self))
}
}
let formatter = ISO8601DateFormatter()
// case 1
do {
// example values
let initTz = TimeZone(abbreviation: "GMT")!
let targetTz = TimeZone(abbreviation: "EST")!
let initDate = Calendar.current.date(from: .init(timeZone: initTz, year: 2020, month: 3, day: 8, hour: 4))!
// usage
let targetDate = initDate.converting(from: initTz, to: targetTz)
// print results
formatter.timeZone = targetTz // case 1 is concerned with what the `Date` looks like in the target time zone
print(formatter.string(from: targetDate)) // 2020-03-08T05:00:00-04:00 (should be 4am)
}
// case 2
do {
// example values
let initTz = TimeZone(abbreviation: "EST")!
let targetTz = TimeZone(abbreviation: "GMT")!
let initDate = Calendar.current.date(from: .init(timeZone: initTz, year: 2020, month: 3, day: 8, hour: 1))!
// usage
let targetDate = initDate.convertingTime(from: initTz, to: targetTz)
// print results
formatter.timeZone = targetTz // for case 2, find the initial `Date`'s time in the target time zone
print(formatter.string(from: initDate)) // 2020-03-08T06:00:00Z (the target date should have this same time)
formatter.timeZone = initTz // case 2 is concerned with what the `Date` looks like in the initial time zone
print(formatter.string(from: targetDate)) // 2020-03-08T07:00:00-04:00 (should be 6am)
}
If you adjust the example dates just a few hours forwards or backwards, the bug does not occur. Calendrical calculations are complex, and attempting to roll your own will almost always result in buggy edge cases. Since a time zone is a calendrical unit, to avoid bugs, you should use the existing Calendar interface, as in my initial example.
runs more effeciently
extension Date {
func convertToLocalTime(fromTimeZone timeZoneAbbreviation: String) -> Date? {
if let timeZone = TimeZone(abbreviation: timeZoneAbbreviation) {
let targetOffset = TimeInterval(timeZone.secondsFromGMT(for: self))
let localOffeset = TimeInterval(TimeZone.autoupdatingCurrent.secondsFromGMT(for: self))
return self.addingTimeInterval(targetOffset - localOffeset)
}
return nil
}
}
Based on mukaissi's answer, but the order of deductible in the expression has been corrected.
extension Date {
func convert(from initTimeZone: TimeZone, to targetTimeZone: TimeZone) -> Date {
let delta = TimeInterval(initTimeZone.secondsFromGMT() - targetTimeZone.secondsFromGMT())
return addingTimeInterval(delta)
}
}
Since NSDate is always in GMT/UTC the time zone only becomes relevant when displaying it to, or getting it from, the user. Just always assume it's UTC internally, convert it for the user (by setting it on the NSDateFormatter) as necessary, and you no longer have to worry about the problem.
So this is mukaissi's answer enhanced with valeCocoa's suggestion for daylight saving time:
func convert(from initTimeZone: TimeZone, to targetTimeZone: TimeZone) -> Date {
let delta = TimeInterval(targetTimeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}
The answer from dbplunkett is exactly right that daylight saving time isn't effectively handled by using secondsFromGMT(for: date), however their extension example is for Calendar. The below extension is for date which achieves the same aim:
extension Date {
func convert(from timeZone: TimeZone, to destinationTimeZone: TimeZone) -> Date {
let calendar = Calendar.current
var components = calendar.dateComponents(in: timeZone, from: self)
components.timeZone = destinationTimeZone
return calendar.date(from: components)!
}
}
Details
Xcode 11.4.1 (11E503a), Swift 5.2
Solution 1
Based on mukaissi answer
import Foundation
extension Date {
func to(timeZone outputTimeZone: TimeZone, from inputTimeZone: TimeZone) -> Date {
let delta = TimeInterval(outputTimeZone.secondsFromGMT(for: self) - inputTimeZone.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}
}
Usage of solution 1
let utcTimeZone = TimeZone(abbreviation: "UTC")!
let dateString = "2020-06-03T01:43:44.888Z"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date = dateFormatter.date(from: dateString)
print(date)
print(date?.to(timeZone: .autoupdatingCurrent, from: utcTimeZone))
print(date?.to(timeZone: .current, from: utcTimeZone))
print(date?.to(timeZone: TimeZone(abbreviation: "PDT")!, from: utcTimeZone))
Solution 2
Do not forget to paste the Solution 1 code here
extension DateFormatter {
func date(from string: String, timeZoneInString: TimeZone, outputTimeZone: TimeZone = .autoupdatingCurrent) -> Date? {
date(from: string)?.to(timeZone: outputTimeZone, from: timeZoneInString)
}
}
Usage of solution 2
let utcTimeZone = TimeZone(abbreviation: "UTC")!
let pdtTimeZone = TimeZone(abbreviation: "PDT")!
let dateString = "2020-06-03T01:43:44.888Z"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
print(dateFormatter.date(from: dateString))
print(dateFormatter.date(from: dateString, timeZoneInString: utcTimeZone))
print(dateFormatter.date(from: dateString, timeZoneInString: utcTimeZone, outputTimeZone: pdtTimeZone))
I suggest
you set the GMT timezone on your dateFormatter to get back directly a NSDate in UTC (having only NSDates in UTC is a good practice)
when you need to display it you use another NSDateFormatter with the local time zone set on it (it is by default)
when you need to send a date to your server, you use dateFormatter again to generate a string
Find GMT ( Time Difference )
func findGMT() -> (hour: Int, minute: Int, second: Int) {
var formatterOnlyHour: DateFormatter = {
let formatter1 = DateFormatter()
formatter1.dateFormat = "HH"
formatter1.locale = Locale(identifier: Locale.preferredLanguages.first ?? "en")
return formatter1
}()
var hourGMT: Int = (Int(formatterOnlyHour.string(from: Date())) ?? 0) - (Int(Date().preciseGMTTime) ?? 0)
// print("Your GMT: \(GMTvalue)")
var minuteGMT: Int = hourGMT * 60
var secondGMT: Int = hourGMT * 3600
return (hourGMT, minuteGMT, secondGMT)}
Extention 1:
extension Formatter {
// create static date formatters for your date representations
static let preciseLocalTime: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH"
return formatter
}()
static let preciseGMTTime: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "HH"
return formatter
}()}
Extention 2:
extension Date {
// you can create a read-only computed property to return just the nanoseconds from your date time
var nanosecond: Int { return Calendar.current.component(.nanosecond, from: self) }
// the same for your local time
var preciseLocalTime: String {
return Formatter.preciseLocalTime.string(for: self) ?? ""
}
// or GMT time
var preciseGMTTime: String {
return Formatter.preciseGMTTime.string(for: self) ?? ""
}}
Related
How can I get local date and time in Swift?
let last_login = String(NSDate.date())
update: Xcode 8.2.1 • Swift 3.0.2
You can also use the Date method description(with locale: Locale?) to get user's localized time description:
A string representation of the Date, using the given locale, or if the locale
argument is nil, in the international format YYYY-MM-DD HH:MM:SS
±HHMM, where ±HHMM represents the time zone offset in hours and
minutes from UTC (for example, “2001-03-24 10:45:32 +0600”).
description(with locale: Locale?)
Date().description(with: .current) // "Monday, February 9, 2015 at 05:47:51 Brasilia Summer Time"
The method above it is not meant to use when displaying date and time to the user. It is for debugging purposes only.
When displaying local date and time (current timezone) to the user you should respect the users locale and device settings. The only thing you can control is the date and time style (short, medium, long or full). Fore more info on that you can check this post shortDateTime.
If your intent is to create a time stamp UTC for encoding purposes (iso8601) you can check this post iso8601
In case you want to get a Date object and not a string representation you can use the following snippet:
extension Date {
func localDate() -> Date {
let nowUTC = Date()
let timeZoneOffset = Double(TimeZone.current.secondsFromGMT(for: nowUTC))
guard let localDate = Calendar.current.date(byAdding: .second, value: Int(timeZoneOffset), to: nowUTC) else {return Date()}
return localDate
}
}
Use it like this:
let now = Date().localDate()
Leo's answer great. I just wanted to add a way to use it as a computed property.
var currentTime: String {
Date().description(with: .current)
}
Use it like so:
print(currentTime)
Or you can encapsulate it:
extension String {
static var currentTime: String {
Date().description(with: .current)
}
}
And then you can use it anywhere you use a string:
var time: String = .currentTime
use NSDateFormatter, either by setting the format
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "hh:mm"
println(dateFormatter.stringFromDate(NSDate()))
or styles
dateFormatter.dateStyle = .NoStyle
dateFormatter.timeStyle = .MediumStyle
I already found the answer.
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
let dateInFormat = dateFormatter.stringFromDate(NSDate())
let expiryDate: Date = ...
let localizedDateString = DateFormatter.localizedString(from: expiryDate, dateStyle: .medium, timeStyle: .short)
"10 Sep 2017, 14:37"
To get back the most common string formats (when dealing with queries and databases):
Swift 4, 5
2019-01-09T01:07:04Z (RFC3339 in GMT/Zulu time)
let f = ISO8601DateFormatter()
f.formatOptions = [.withInternetDateTime]
let s = f.string(from: Date())
2019-01-08T17:04:16-08:00 (RFC3339 accounting for local time zone)
let f = ISO8601DateFormatter()
f.formatOptions = [.withInternetDateTime]
f.timeZone = TimeZone.current
let s = f.string(from: Date())
2019-01-09 (standard date stamp in GMT/Zulu time)
let f = ISO8601DateFormatter()
f.formatOptions = [.withFullDate, .withDashSeparatorInDate]
let s = f.string(from: Date())
2019-01-08 (standard date stamp accounting for local time zone)
let f = ISO8601DateFormatter()
f.formatOptions = [.withFullDate, .withDashSeparatorInDate]
f.timeZone = TimeZone.current
let s = f.string(from: Date())
All four strings represent the exact same point in time. And remember that sorting these strings in alphabetical order also sorts them into chronological order, which makes this data database agnostic (which I always aim for).
You have to use NSDateFormatter
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy HH:mm"
dateFormatter.locale = "en" // Change "en" to change the default locale if you want
let stringDate = dateFormatter.stringFromDate(date)
Refactor the answer with swift 5 base on #lajosdeme. My location is in China.
import Foundation
let date = Date() // It is not the local time, less than 8 hours
print(date) // 2022-08-05 08:04:20 +0000
extension Date {
static func localDate() -> Date {
let nowUTC = Date()
let timeZoneOffset = Double(TimeZone.current.secondsFromGMT(for: nowUTC))
guard let localDate = Calendar.current.date(byAdding: .second, value: Int(timeZoneOffset), to: nowUTC) else {
return nowUTC
}
return localDate
}
}
// It is the local time
print(Date.localDate()) // 2022-08-05 16:04:20 +0000
Swift 4
To get current date and time
let currentDate = Date()
print(currentDate) //this will return current date and time
but that will be in date type to convert date into string
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm" //give the formate according to your need
let dateStr = dateFormatter.string(from: currentDate) //which will give the string of current date and time in required dateformate
My understanding of Swift Date is that Date is a time point without any calendar or timezone information. I think it is GMT time. If you want to show a date in a specified timezone, you have to use DateFormat API to format the date to a string.
I have an iOS app TapToCount-3W to make notes with date and GPS location information. When I travel, I use it to record/tap a note with date and GPS. The dates are local date when I am in travel countries. However, the problem I found is that when I come back home, the travel dates displayed are in my home country dates instead of those travel country timezones.
I am working on updates with my app now. The solution is to add timezone information when a tap is made. With date and timezone information, the localized dates will be correctly displayed.
The method as recommended in this QA to extend Date is actually to create date from Date() from second offset from GMT time. It is a GMT time and different date from Date().
The following codes are from my updates(I also included #lajosdeme method as comparison):
extension Date {
private func getLocalByID(_ identifier: String?) -> Locale
{
let local: Locale
if let id = identifier, !id.isEmpty {
local = Locale(identifier: id)
} else {
local = Locale.current
}
return local
}
func localizedString(
timezone: String?,
dateStyle: DateFormatter.Style = .short,
timeStyle: DateFormatter.Style = .long
) -> String
{
let dtFormater = DateFormatter()
let tz: String = timezone ?? ""
dtFormater.locale = getLocalByID(tz)
dtFormater.dateStyle = dateStyle
dtFormater.timeStyle = timeStyle
if let timeZone = TimeZone(identifier: tz) {
dtFormater.timeZone = timeZone
}
return dtFormater.string(from: self)
}
func dateForTimezone(_ timezone: String?) -> Date {
let nowUTC = Date()
let tz: TimeZone
if let timezone = timezone,
let v = TimeZone(identifier: timezone)
{
tz = v
} else {
tz = TimeZone.current
}
let timeZoneOffset =
Double(tz.secondsFromGMT(for: nowUTC))
if let dt =
Calendar.current.date(byAdding: .second, value: Int(timeZoneOffset), to: nowUTC)
{
return dt
}
else {
return Date()
}
}
}
// Test above extension in Playground
// [SwiftFiddle][3]
let dt1 = Date()
let tz = "America/Edmonton"
let dt2 = dt1.description(with: .current)
let dt3 = dt1.localizedString(timezone: tz)
let dt4 = dt1.dateForTimezone(tz)
print("Timezone: \(tz)\nDate: \(dt1)\ndescription: \(dt2)\nlocalized string: \(dt3)\ndateForTimezone: \(dt4)")
Here are the test result from SwiftFiddle playground:
Timezone: America/Edmonton
Date: 2022-06-03 15:41:23 +0000
description: Friday, June 3, 2022 at 3:41:23 PM Coordinated Universal Time
localized string: 6/3/22, 9:41:23 AM GMT-6
dateForTimezone: 2022-06-03 09:41:23 +0000
I had set time to San Carlos California(PDT Timezone) in my I phone, then I am trying to add 30 days which is fine , but when I am trying to convert that Date object to IST Timezone , it is not correct.
11/19/2020 06:46:25
Above one is days added by 30 in todays date, In San Calos(PDT Timezone)
when I am converting that time in IST it is "11/18/2020 at 11:46 PM"
but it should be "11/18/2020 at 19:46"
time is variant..
I am using this to convert time into IST
Convert date to local TimeZone
func convertExpiryToIst(inputFormat: String, outputFormat: String) -> String{
let formatter = DateFormatter()
formatter.dateFormat = inputFormat
formatter.timeZone = TimeZone.current
var date = formatter.date(from: self)
date?.addTimeInterval(TimeInterval(value))
formatter.dateFormat = outputFormat
if date != nil {
print(date)
return formatter.string(from: date!)
}
return self
}
The issue there is that you are adding a time interval to the resulting date. A date has no timezone it is just a point in time. All you need to do is to change the date formatter timezone to the desired one and get the string representation of it.
extension String {
func convertExpiryTo(inputFormat: String, inputTimeZone: String, outputFormat: String, outputTimeZone: String)-> String? {
let formatter = DateFormatter()
formatter.dateFormat = inputFormat
formatter.timeZone = TimeZone(identifier: inputTimeZone)
if let date = formatter.date(from: self) {
// let offset = TimeZone(abbreviation: "IST")!.secondsFromGMT(for: date) - TimeZone(abbreviation: "PDT")!.secondsFromGMT(for: date)
// let hours = Double(offset) / 3600 // 13.5 hours
// dont add the timezone offset
// date?.addTimeInterval(TimeInterval(value))
formatter.dateFormat = outputFormat
// just set a different timezone
formatter.timeZone = TimeZone(identifier: outputTimeZone)
return formatter.string(from: date)
}
return nil
}
}
"11/19/2020 06:46:25".convertExpiry(inputFormat: "MM/dd/yyyy HH:mm:ss", inputTimeZone: "America/Los_Angeles", outputFormat: "MM/dd/yyyy 'at' h:mm a", outputTimeZone: "Asia/Kolkata") // "11/19/2020 at 8:16 PM" = +13.5 hours
I'm trying to make an attendance app and I am really confused about date and time in iOS and Firebase.
I use date as Key, this is the structure of my Firebase database.
--Employees
--Unique_ID
--Details
Name: John
--Attendance
--dateToday
Timein: 8:00 AM
Timeout: 5:00 PM
BreakStart: 12:00 PM
BreakFinish: 1:00 PM
This is my code to get the date timestamp I used as Key
override func viewDidLoad() {
super.viewDidLoad()
let now = NSDate()
let nowTimeStamp = self.getCurrentTimeStampWOMiliseconds(dateToConvert: now)
// I save this dateToday as Key in Firebase
dateToday = nowTimeStamp
}
func getCurrentTimeStampWOMiliseconds(dateToConvert: NSDate) -> String {
let objDateformat: DateFormatter = DateFormatter()
objDateformat.dateFormat = "yyyy-MM-dd"
let strTime: String = objDateformat.string(from: dateToConvert as Date)
let objUTCDate: NSDate = objDateformat.date(from: strTime)! as NSDate
let milliseconds: Int64 = Int64(objUTCDate.timeIntervalSince1970)
let strTimeStamp: String = "\(milliseconds)"
return strTimeStamp
}
But when I convert it back to date I get 2017-09-22 16:00:00 +0000, which is wrong because it is 23rd of September in my location.
What is the right code to use so that I can get the correct date timestamp and time timestamp?
For saving Current time to firebase database I use Unic Epoch Conversation:
let timestamp = NSDate().timeIntervalSince1970
and For Decoding Unix Epoch time to Date().
let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))
If you just want the unix timestamp, create an extension:
extension Date {
func currentTimeMillis() -> Int64 {
return Int64(self.timeIntervalSince1970 * 1000)
}
}
Then you can use it just like in other programming languages:
let timestamp = Date().currentTimeMillis()
First I would recommend you to store your timestamp as a NSNumber in your Firebase Database, instead of storing it as a String.
Another thing worth mentioning here, is that if you want to manipulate dates with Swift, you'd better use Date instead of NSDate, except if you're interacting with some Obj-C code in your app.
You can of course use both, but the Documentation states:
Date bridges to the NSDate class. You can use these interchangeably in
code that interacts with Objective-C APIs.
Now to answer your question, I think the problem here is because of the timezone.
For example if you print(Date()), as for now, you would get:
2017-09-23 06:59:34 +0000
This is the Greenwich Mean Time (GMT).
So depending on where you are located (or where your users are located) you need to adjust the timezone before (or after, when you try to access the data for example) storing your Date:
let now = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let dateString = formatter.string(from: now)
Then you have your properly formatted String, reflecting the current time at your location, and you're free to do whatever you want with it :) (convert it to a Date / NSNumber, or store it directly as a String in the database..)
in Swift 5
extension Date {
static var currentTimeStamp: Int64{
return Int64(Date().timeIntervalSince1970 * 1000)
}
}
call like this:
let timeStamp = Date.currentTimeStamp
print(timeStamp)
Thanks #lenooh
The simple way to create Current TimeStamp. like below,
func generateCurrentTimeStamp () -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy_MM_dd_hh_mm_ss"
return (formatter.string(from: Date()) as NSString) as String
}
you can call like this:
let timeStmp = generateCurrentTimeStamp()
print("time stamp: \(timeStmp)")
If you code for iOS 13.0 or later and want a timestamp, then you can use:
let currentDate = NSDate.now
On expanding #MacacoAzul's answer here is my current working example :
import SwiftUI
struct TimestampDemo: View {
var body: some View {
Text(getActualTimeStamp(1))
.padding(10)
Text(getActualTimeStamp(2))
.padding(10)
Text(getActualTimeStamp(3))
.padding(10)
Text(getActualTimeStamp(4))
.padding(10)
}
func getActualTimeStamp(_ tipo:Int) -> String {
let date = Date()
let formatter = DateFormatter()
if tipo == 1{
formatter.dateFormat = "dd/MM/yyyy"
} else if tipo == 2{
formatter.dateFormat = "yyyy-MM-dd HH:mm"
}else if tipo == 3{
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
}
else if tipo == 4 {
formatter.dateFormat = "dd-MM-yyyy"
}
return formatter.string(from: date)
}
}
struct TimestampDemo_Previews: PreviewProvider {
static var previews: some View {
TimestampDemo()
}
}
Swift Language Version : 5
When we convert a UTC timestamp (2017-11-06 20:15:33 -08:00) into a Date object, the time zone is zeroed out to GMT. For calculating time intervals, this isn't an issue, but it can be for rendering times in the UI.
I favor the RFC3339 format (2017-11-06T20:15:33-08:00) for its universality. The date format in Swift is yyyy-MM-dd'T'HH:mm:ssXXXXX but RFC3339 allows us to take advantage of the ISO8601DateFormatter:
func getDateFromUTC(RFC3339: String) -> Date? {
let formatter = ISO8601DateFormatter()
return formatter.date(from: RFC3339)
}
RFC3339 also makes time-zone extraction simple:
func getTimeZoneFromUTC(RFC3339: String) -> TimeZone? {
switch RFC3339.suffix(6) {
case "+05:30":
return TimeZone(identifier: "Asia/Kolkata")
case "+05:45":
return TimeZone(identifier: "Asia/Kathmandu")
default:
return nil
}
}
There are 37 or so other time zones we'd have to account for and it's up to you to determine which ones, because there is no definitive list. Some standards count fewer time zones, some more. Most time zones break on the hour, some on the half hour, some on 0:45, some on 0:15.
We can combine the two methods above into something like this:
func getFormattedDateFromUTC(RFC3339: String) -> String? {
guard let date = getDateFromUTC(RFC3339: RFC3339),
let timeZone = getTimeZoneFromUTC(RFC3339: RFC3339) else {
return nil
}
let formatter = DateFormatter()
formatter.dateFormat = "h:mma EEE, MMM d yyyy"
formatter.amSymbol = "AM"
formatter.pmSymbol = "PM"
formatter.timeZone = timeZone // preserve local time zone
return formatter.string(from: date)
}
And so the string "2018-11-06T17:00:00+05:45", which represents 5:00PM somewhere in Kathmandu, will print 5:00PM Tue, Nov 6 2018, displaying the local time, regardless of where the machine is.
As an aside, I recommend storing dates as strings remotely (including Firestore which has a native date object) because, I think, remote data should agnostic to create as little friction between servers and clients as possible.
you can even create a function to return different time stamps depending on your necessity:
func dataatual(_ tipo:Int) -> String {
let date = Date()
let formatter = DateFormatter()
if tipo == 1{
formatter.dateFormat = "dd/MM/yyyy"
} else if tipo == 2{
formatter.dateFormat = "yyyy-MM-dd HH:mm"
} else {
formatter.dateFormat = "dd-MM-yyyy"
}
return formatter.string(from: date)
}
I am working for an application written in swift and i want to manipulate dates and times
let timestamp = NSDateFormatter.localizedStringFromDate(
NSDate(),
dateStyle: .ShortStyle,
timeStyle: .ShortStyle
)
returns
2/12/15, 11:27 PM
if I want date and time in a different format, for example the date in a European format like dd/mm/yy and the hours in the 24h format without AM and PM. Is there some function that i can use or i have to use N Strings to reorder the various elements?
func convertDateFormater(date: String) -> String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
guard let date = dateFormatter.dateFromString(date) else {
assert(false, "no date from string")
return ""
}
dateFormatter.dateFormat = "yyyy MMM EEEE HH:mm"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let timeStamp = dateFormatter.stringFromDate(date)
return timeStamp
}
Edit for Swift 4
func convertDateFormatter(date: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"//this your string date format
dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
dateFormatter.locale = Locale(identifier: "your_loc_id")
let convertedDate = dateFormatter.date(from: date)
guard dateFormatter.date(from: date) != nil else {
assert(false, "no date from string")
return ""
}
dateFormatter.dateFormat = "yyyy MMM HH:mm EEEE"///this is what you want to convert format
dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
let timeStamp = dateFormatter.string(from: convertedDate!)
return timeStamp
}
As already mentioned you have to use DateFormatter to format your Date objects. The easiest way to do it is creating a read-only computed property Date extension.
Read-Only Computed Properties
A computed property with a getter but no setter is known as a
read-only computed property. A read-only computed property always
returns a value, and can be accessed through dot syntax, but cannot be
set to a different value.
Note:
You must declare computed properties—including read-only computed
properties—as variable properties with the var keyword, because their
value is not fixed. The let keyword is only used for constant
properties, to indicate that their values cannot be changed once they
are set as part of instance initialization.
You can simplify the declaration of a read-only computed property by
removing the get keyword and its braces:
extension Formatter {
static let date = DateFormatter()
}
extension Date {
var europeanFormattedEn_US : String {
Formatter.date.calendar = Calendar(identifier: .iso8601)
Formatter.date.locale = Locale(identifier: "en_US_POSIX")
Formatter.date.timeZone = .current
Formatter.date.dateFormat = "dd/M/yyyy, H:mm"
return Formatter.date.string(from: self)
}
}
To convert it back you can create another read-only computed property but as a string extension:
extension String {
var date: Date? {
return Formatter.date.date(from: self)
}
func dateFormatted(with dateFormat: String = "dd/M/yyyy, H:mm", calendar: Calendar = Calendar(identifier: .iso8601), defaultDate: Date? = nil, locale: Locale = Locale(identifier: "en_US_POSIX"), timeZone: TimeZone = .current) -> Date? {
Formatter.date.calendar = calendar
Formatter.date.defaultDate = defaultDate ?? calendar.date(bySettingHour: 12, minute: 0, second: 0, of: Date())
Formatter.date.locale = locale
Formatter.date.timeZone = timeZone
Formatter.date.dateFormat = dateFormat
return Formatter.date.date(from: self)
}
}
Usage:
let dateFormatted = Date().europeanFormattedEn_US //"29/9/2018, 16:16"
if let date = dateFormatted.date {
print(date.description(with:.current)) // Saturday, September 29, 2018 at 4:16:00 PM Brasilia Standard Time\n"\
date.europeanFormattedEn_US // "29/9/2018, 16:27"
}
let dateString = "14/7/2016"
if let date = dateString.toDateFormatted(with: "dd/M/yyyy") {
print(date.description(with: .current))
// Thursday, July 14, 2016 at 12:00:00 PM Brasilia Standard Time\n"
}
As Zaph stated, you need to follow the documentation. Admittedly it may not be the most straightforward when compared to other class references. The short answer is, you use Date Field Symbol Table to figure out what format you want. Once you do:
let dateFormatter = NSDateFormatter()
//the "M/d/yy, H:mm" is put together from the Symbol Table
dateFormatter.dateFormat = "M/d/yy, H:mm"
dateFormatter.stringFromDate(NSDate())
You'll also need to be able to use the table if you need to convert a date that is a string into an NSDate.
let dateAsString = "02/12/15, 16:48"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "M/d/yyyy, H:mm"
let date = dateFormatter.dateFromString(dateAsString)
Current date time to formated string:
let currentDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy hh:mm:ss a"
let convertedDate: String = dateFormatter.string(from: currentDate) //08/10/2016 01:42:22 AM
More Date Time Formats
You have already found NSDateFormatter, just read the documentation on it.
NSDateFormatter Class Reference
For format character definitions
See: ICU Formatting Dates and Times
Also: Date Field SymbolTable..
If you want to use protocol oriented programming (Swift 3)
1) Create a Dateable protocol
protocol Dateable {
func userFriendlyFullDate() -> String
func userFriendlyHours() -> String
}
2) Extend Date class and implement the Dateable protocol
extension Date: Dateable {
var formatter: DateFormatter { return DateFormatter() }
/** Return a user friendly hour */
func userFriendlyFullDate() -> String {
// Customize a date formatter
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
formatter.timeZone = TimeZone(abbreviation: "UTC")
return formatter.string(from: self)
}
/** Return a user friendly hour */
func userFriendlyHours() -> String {
// Customize a date formatter
formatter.dateFormat = "HH:mm"
formatter.timeZone = TimeZone(abbreviation: "UTC")
return formatter.string(from: self)
}
// You can add many cases you need like string to date formatter
}
3) Use it
let currentDate: Date = Date()
let stringDate: String = currentDate.userFriendlyHours()
// Print 15:16
I used the a similar approach as #iod07, but as an extension.
Also, I added some explanations in the comments to understand how it works.
Basically, just add this at the top or bottom of your view controller.
extension NSString {
class func convertFormatOfDate(date: String, originalFormat: String, destinationFormat: String) -> String! {
// Orginal format :
let dateOriginalFormat = NSDateFormatter()
dateOriginalFormat.dateFormat = originalFormat // in the example it'll take "yy MM dd" (from our call)
// Destination format :
let dateDestinationFormat = NSDateFormatter()
dateDestinationFormat.dateFormat = destinationFormat // in the example it'll take "EEEE dd MMMM yyyy" (from our call)
// Convert current String Date to NSDate
let dateFromString = dateOriginalFormat.dateFromString(date)
// Convert new NSDate created above to String with the good format
let dateFormated = dateDestinationFormat.stringFromDate(dateFromString!)
return dateFormated
}
}
Example
Let's say you want to convert "16 05 05" to "Thursday 05 May 2016" and your date is declared as follow let date = "16 06 05"
Then simply call call it with :
let newDate = NSString.convertFormatOfDate(date, originalFormat: "yy MM dd", destinationFormat: "EEEE dd MMMM yyyy")
Hope it helps !
Here is a solution that works with Xcode 10.1 (FEB 23 2019) :
func getCurrentDateTime() {
let now = Date()
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "fr_FR")
formatter.dateFormat = "EEEE dd MMMM YYYY"
labelDate.text = formatter.string(from: now)
labelDate.font = UIFont(name: "HelveticaNeue-Bold", size: 12)
labelDate.textColor = UIColor.lightGray
let text = formatter.string(from: now)
labelDate.text = text.uppercased()
}
The "Accueil" Label is not connected to the code.
iOS 8+
It is cumbersome and difficult to specify locale explicitly. You never know where your app will be used. So I think, it is better to set locale to Calender.current.locale and use DateFormatter's
setLocalizedDateFormatFromTemplate method.
setLocalizedDateFormatFromTemplate(_:)
Sets the date format from a template using the specified locale for the receiver. - developer.apple.com
extension Date {
func convertToLocaleDate(template: String) -> String {
let dateFormatter = DateFormatter()
let calender = Calendar.current
dateFormatter.timeZone = calender.timeZone
dateFormatter.locale = calender.locale
dateFormatter.setLocalizedDateFormatFromTemplate(template)
return dateFormatter.string(from: self)
}
}
Date().convertToLocaleDate(template: "dd MMMM YYYY")
Swift 3:
//This gives month as three letters (Jun, Dec, etc)
let justMonth = DateFormatter()
justMonth.dateFormat = "MMM"
myFirstLabel.text = justMonth.string(from: myDate)
//This gives the day of month, with no preceding 0s (6,14,29)
let justDay = DateFormatter()
justDay.dateFormat = "d"
mySecondLabel.text = justDay.string(from: myDate)
//This gives year as two digits, preceded by an apostrophe ('09, '16, etc)
let justYear = DateFormatter()
justYear.dateFormat = "yy"
myThirdLabel.text = "'\(justYear.string(from: lastCompDate))"
For more formats, check out this link to a codingExplorer table with all the available formats. Each date component has several options, for example:
Year:
"y" - 2016 (early dates like year 1 would be: "1")
"yy" - 16 (year 1: "01"
"yyy" - 2016 (year 1: "001")
"yyyy" - 2016 (year 1: "0001")
Pretty much every component has 2-4 options, using the first letter to express the format (day is "d", hour is "h", etc). However, month is a capital "M", because the lower case "m" is reserved for minute. There are some other exceptions though, so check out the link!
let usDateFormat = DateFormatter.dateFormat(FromTemplate: "MMddyyyy", options: 0, locale: Locale(identifier: "en-US"))
//usDateFormat now contains an optional string "MM/dd/yyyy"
let gbDateFormat = DateFormatter.dateFormat(FromTemplate: "MMddyyyy", options: 0, locale: Locale(identifier: "en-GB"))
//gbDateFormat now contains an optional string "dd/MM/yyyy"
let geDateFormat = DateFormatter.dateFormat(FromTemplate: "MMddyyyy", options: 0, locale: Locale(identifier: "de-DE"))
//geDateFormat now contains an optional string "dd.MM.yyyy"
You can use it in following way to get the current format from device:
let currentDateFormat = DateFormatter.dateFormat(fromTemplate: "MMddyyyy", options: 0, locale: Locale.current)
Added some formats in one place. Hope someone get help.
Xcode 12 - Swift 5.3
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
var dateFromStr = dateFormatter.date(from: "12:16:45")!
dateFormatter.dateFormat = "hh:mm:ss a 'on' MMMM dd, yyyy"
//Output: 12:16:45 PM on January 01, 2000
dateFormatter.dateFormat = "E, d MMM yyyy HH:mm:ss Z"
//Output: Sat, 1 Jan 2000 12:16:45 +0600
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
//Output: 2000-01-01T12:16:45+0600
dateFormatter.dateFormat = "EEEE, MMM d, yyyy"
//Output: Saturday, Jan 1, 2000
dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
//Output: 01-01-2000 12:16
dateFormatter.dateFormat = "MMM d, h:mm a"
//Output: Jan 1, 12:16 PM
dateFormatter.dateFormat = "HH:mm:ss.SSS"
//Output: 12:16:45.000
dateFormatter.dateFormat = "MMM d, yyyy"
//Output: Jan 1, 2000
dateFormatter.dateFormat = "MM/dd/yyyy"
//Output: 01/01/2000
dateFormatter.dateFormat = "hh:mm:ss a"
//Output: 12:16:45 PM
dateFormatter.dateFormat = "MMMM yyyy"
//Output: January 2000
dateFormatter.dateFormat = "dd.MM.yy"
//Output: 01.01.00
//Output: Customisable AP/PM symbols
dateFormatter.amSymbol = "am"
dateFormatter.pmSymbol = "Pm"
dateFormatter.dateFormat = "a"
//Output: Pm
// Usage
var timeFromDate = dateFormatter.string(from: dateFromStr)
print(timeFromDate)
let dateString = "1970-01-01T13:30:00.000Z"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = formatter.date(from: String(dateString.dropLast(5)))!
formatter.dateFormat = "hh.mma"
print(formatter.string(from: date))
if You notice I have set .dateFormat = "hh.mma"by this you will get time only.
Result:01.30PM
extension String {
func convertDatetring_TopreferredFormat(currentFormat: String, toFormat : String) -> String {
let dateFormator = DateFormatter()
dateFormator.dateFormat = currentFormat
let resultDate = dateFormator.date(from: self)
dateFormator.dateFormat = toFormat
return dateFormator.string(from: resultDate!)
}
}
Call from your view controller file as below.
"your_date_string".convertDatetring_TopreferredFormat(currentFormat: "yyyy-MM-dd HH:mm:ss.s", toFormat: "dd-MMM-yyyy h:mm a")
This is possibly an old thread but I was working on datetimes recently and was stuck with similar issue so I ended up creating a utility of mine which looks like this,
This utility would take a string date and would return an optional date object
func toDate(dateFormat: DateFormatType) -> Date? {
let formatter = DateFormatter()
formatter.timeZone = NSTimeZone(name: "UTC") as TimeZone?
formatter.dateFormat = dateFormat.rawValue
let temp = formatter.date(from: self)
return formatter.date(from: self)
}
the DateFormatType enum looks like this
enum DateFormatType : String {
case type1 = "yyyy-MM-dd - HH:mm:ss"
case type2 = "dd/MM/yyyy"
case type3 = "yyyy/MM/dd"
}
One important thing I would like to mention here is the line
formatter.timeZone = NSTimeZone(name: "UTC") as TimeZone?
it's very important that you add this line because without this the DateFormatter would use it's default conversions to convert the date and you might end up seeing different dates if you are working with a remote team and get all sorts of issues with data depending on dates.
Hope this helps
Time Picker In swift
class ViewController: UIViewController {
//timePicker
#IBOutlet weak var lblTime: UILabel!
#IBOutlet weak var timePicker: UIDatePicker!
#IBOutlet weak var cancelTime_Btn: UIBarButtonItem!
#IBOutlet weak var donetime_Btn: UIBarButtonItem!
#IBOutlet weak var toolBar: UIToolbar!
//Date picker
// #IBOutlet weak var datePicker: UIDatePicker!
override func viewDidLoad() {
super.viewDidLoad()
ishidden(bool: true)
let dateFormatter2 = DateFormatter()
dateFormatter2.dateFormat = "HH:mm a" //"hh:mm a"
lblTime.text = dateFormatter2.string(from: timePicker.date)
}
#IBAction func selectTime_Action(_ sender: Any) {
timePicker.datePickerMode = .time
ishidden(bool: false)
}
#IBAction func timeCancel_Action(_ sender: Any) {
ishidden(bool: true)
}
#IBAction func timeDoneBtn(_ sender: Any) {
let dateFormatter1 = DateFormatter()
dateFormatter1.dateFormat = "HH:mm a"//"hh:mm"
let str = dateFormatter1.string(from: timePicker.date)
lblTime.text = str
ishidden(bool: true)
}
func ishidden(bool:Bool){
timePicker.isHidden = bool
toolBar.isHidden = bool
}
}
new Date(year,month,day,0,0,0,0) is local time (as input)
new Date(year,month,day) is UTC
I was using a function to attain YYYY-MM-DD format to be compatible on iOS web, but that is also UTC when used in comparisons (not chained by getFullYear or similar) I've found it is best to use only the above with strong (hours,minutes,seconds,milliseconds) building a calendar, calculating with a Date objects and local references
export const zeroPad = (num) => {
var res = "0";
if (String(num).length === 1) {
res = `0${num}`;
} else {
res = num;
}
return res;
};
How do you create a date object from a date in swift xcode.
eg in javascript you would do:
var day = new Date('2014-05-20');
Swift has its own Date type. No need to use NSDate.
Creating a Date and Time in Swift
In Swift, dates and times are stored in a 64-bit floating point number measuring the number of seconds since the reference date of January 1, 2001 at 00:00:00 UTC. This is expressed in the Date structure. The following would give you the current date and time:
let currentDateTime = Date()
For creating other date-times, you can use one of the following methods.
Method 1
If you know the number of seconds before or after the 2001 reference date, you can use that.
let someDateTime = Date(timeIntervalSinceReferenceDate: -123456789.0) // Feb 2, 1997, 10:26 AM
Method 2
Of course, it would be easier to use things like years, months, days and hours (rather than relative seconds) to make a Date. For this you can use DateComponents to specify the components and then Calendar to create the date. The Calendar gives the Date context. Otherwise, how would it know what time zone or calendar to express it in?
// Specify date components
var dateComponents = DateComponents()
dateComponents.year = 1980
dateComponents.month = 7
dateComponents.day = 11
dateComponents.timeZone = TimeZone(abbreviation: "JST") // Japan Standard Time
dateComponents.hour = 8
dateComponents.minute = 34
// Create date from components
let userCalendar = Calendar(identifier: .gregorian) // since the components above (like year 1980) are for Gregorian
let someDateTime = userCalendar.date(from: dateComponents)
Other time zone abbreviations can be found here. If you leave that blank, then the default is to use the user's time zone.
Method 3
The most succinct way (but not necessarily the best) could be to use DateFormatter.
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let someDateTime = formatter.date(from: "2016/10/08 22:31")
The Unicode technical standards show other formats that DateFormatter supports.
Notes
See my full answer for how to display the date and time in a readable format. Also read these excellent articles:
How to work with dates and times in Swift 3, part 1: Dates, Calendars, and DateComponents
How to work with dates and times in Swift 3, part 2: DateFormatter
How to work with dates and times in Swift 3, part 3: Date arithmetic
This is best done using an extension to the existing NSDate class.
The following extension adds a new initializer which will create a date in the current locale using the date string in the format you specified.
extension NSDate
{
convenience
init(dateString:String) {
let dateStringFormatter = NSDateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let d = dateStringFormatter.dateFromString(dateString)!
self.init(timeInterval:0, sinceDate:d)
}
}
Now you can create an NSDate from Swift just by doing:
NSDate(dateString:"2014-06-06")
Please note that this implementation does not cache the NSDateFormatter, which you might want to do for performance reasons if you expect to be creating many NSDates in this way.
Please also note that this implementation will simply crash if you try to initialize an NSDate by passing in a string that cannot be parsed correctly. This is because of the forced unwrap of the optional value returned by dateFromString. If you wanted to return a nil on bad parses, you would ideally use a failible initializer; but you cannot do that now (June 2015), because of a limitation in Swift 1.2, so then you're next best choice is to use a class factory method.
A more elaborate example, which addresses both issues, is here: https://gist.github.com/algal/09b08515460b7bd229fa .
Update for Swift 5
extension Date {
init(_ dateString:String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
let date = dateStringFormatter.date(from: dateString)!
self.init(timeInterval:0, since:date)
}
}
Swift doesn't have its own Date type, but you to use the existing Cocoa NSDate type, e.g:
class Date {
class func from(year: Int, month: Int, day: Int) -> Date {
let gregorianCalendar = NSCalendar(calendarIdentifier: .gregorian)!
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
let date = gregorianCalendar.date(from: dateComponents)!
return date
}
class func parse(_ string: String, format: String = "yyyy-MM-dd") -> Date {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = NSTimeZone.default
dateFormatter.dateFormat = format
let date = dateFormatter.date(from: string)!
return date
}
}
Which you can use like:
var date = Date.parse("2014-05-20")
var date = Date.from(year: 2014, month: 05, day: 20)
Here's how I did it in Swift 4.2:
extension Date {
/// Create a date from specified parameters
///
/// - Parameters:
/// - year: The desired year
/// - month: The desired month
/// - day: The desired day
/// - Returns: A `Date` object
static func from(year: Int, month: Int, day: Int) -> Date? {
let calendar = Calendar(identifier: .gregorian)
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
return calendar.date(from: dateComponents) ?? nil
}
}
Usage:
let marsOpportunityLaunchDate = Date.from(year: 2003, month: 07, day: 07)
According to Apple documentation
Example :
var myObject = NSDate()
let futureDate = myObject.dateByAddingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow
According to #mythz answer, I decide to post updated version of his extension using swift3 syntax.
extension Date {
static func from(_ year: Int, _ month: Int, _ day: Int) -> Date?
{
let gregorianCalendar = Calendar(identifier: .gregorian)
let dateComponents = DateComponents(calendar: gregorianCalendar, year: year, month: month, day: day)
return gregorianCalendar.date(from: dateComponents)
}
}
I don't use parse method, but if someone needs, I will update this post.
In, Swift 3.0 you have set date object for this way.
extension Date
{
init(dateString:String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = Locale(identifier: "en_US_POSIX")
let d = dateStringFormatter.date(from: dateString)!
self(timeInterval:0, since:d)
}
}
According to Apple's Data Formatting Guide
Creating a date formatter is not a cheap operation. If you are likely
to use a formatter frequently, it is typically more efficient to cache
a single instance than to create and dispose of multiple instances.
One approach is to use a static variable
And while I agree with #Leon that this should preferably be a failable initializer, it doesn't always have to be (just like there is UIImage(imageLiteralResourceName:) that will crash if the resource doesn't exist).
So here's my approach:
extension DateFormatter {
static let yyyyMMdd: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
extension Date {
init?(yyyyMMdd: String) {
guard let date = DateFormatter.yyyyMMdd.date(from: yyyyMMdd) else { return nil }
self.init(timeInterval: 0, since: date)
}
init(dateLiteralString yyyyMMdd: String) {
let date = DateFormatter.yyyyMMdd.date(from: yyyyMMdd)!
self.init(timeInterval: 0, since: date)
}
}
And now enjoy simply calling:
// For cases where the date exists for sure (eg. seed data)
Date(dateLiteralString: "2020-03-30")
// The rest of the time (eg. parsing unknown data)
guard let date = Date(yyyyMMdd: "2020-03-30") else { return nil }
Personally I think it should be a failable initialiser:
extension Date {
init?(dateString: String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
if let d = dateStringFormatter.date(from: dateString) {
self.init(timeInterval: 0, since: d)
} else {
return nil
}
}
}
Otherwise a string with an invalid format will raise an exception.
I often have a need to combine date values from one place with time values for another. I wrote a helper function to accomplish this.
let startDateTimeComponents = NSDateComponents()
startDateTimeComponents.year = NSCalendar.currentCalendar().components(NSCalendarUnit.Year, fromDate: date).year
startDateTimeComponents.month = NSCalendar.currentCalendar().components(NSCalendarUnit.Month, fromDate: date).month
startDateTimeComponents.day = NSCalendar.currentCalendar().components(NSCalendarUnit.Day, fromDate: date).day
startDateTimeComponents.hour = NSCalendar.currentCalendar().components(NSCalendarUnit.Hour, fromDate: time).hour
startDateTimeComponents.minute = NSCalendar.currentCalendar().components(NSCalendarUnit.Minute, fromDate: time).minute
let startDateCalendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
combinedDateTime = startDateCalendar!.dateFromComponents(startDateTimeComponents)!
Since iOS15, Xcode 13 you can also create simple dates like this:
let date = try? Date("2022-02-14T20:15:00Z", strategy: .iso8601)