44

How can I get local date and time in Swift?

let last_login = String(NSDate.date())
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Nurdin
  • 23,382
  • 43
  • 130
  • 308
  • 2
    Found a fantastic site to help figure out your format string: http://nsdateformatter.com/ – Eric Jun 30 '16 at 11:56

11 Answers11

67

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

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    Hi there, and how to convert this huge string to simple date?? dd/MM/yyyy HH:mm:ss ?? – Daniel Arantes Loverde Nov 26 '18 at 18:14
  • 1
    Are you trying to display it to the user or send it to your server as iso8601 date string ? The method above is for debugging purposes only. – Leo Dabus Nov 26 '18 at 18:16
  • and this https://stackoverflow.com/questions/28016578/how-to-create-a-date-time-stamp-and-format-as-iso-8601-rfc-3339-utc-time-zone/28016692#28016692 – Leo Dabus Feb 12 '19 at 03:03
  • @LeoDabus Is it possible to show Brasilia Summer Time as BST? – Samiul Islam Sami Oct 18 '20 at 12:19
  • @SamiulIslamSami be careful when using abbreviations. It is ambiguous. BST can be interpreted as British summer time as well. You should always use the identifiers. – Leo Dabus Dec 14 '21 at 14:17
35

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()
lajosdeme
  • 2,189
  • 1
  • 11
  • 20
  • @LeoDabus care to elaborate? – lajosdeme Jul 09 '20 at 09:10
  • A date is just a point in time. It has no timezone (actually it is the number of seconds since 00:00:00 UTC on 1 January 2001). Only the string representation of a date can have a timezone – Leo Dabus Jul 09 '20 at 09:21
  • 3
    From the docs **A Date value encapsulate a single point in time, independent of any particular calendrical system or time zone. Date values represent a time interval relative to an absolute reference date.** – Leo Dabus Jul 09 '20 at 09:24
  • So if you would like to understand what I mean try `let localDate = Date().localDate()` then `print(localDate.description(with: .current))` and check the result – Leo Dabus Jul 09 '20 at 09:26
  • 7
    This answer is the wrong way to handle dates. Do not do this. As Leo Dabus says in his comment, a Date object captures a moment in time, independent of a time zone, and forcing a date to a different date that displays the correct time in UTC is completely wrong. – Duncan C Feb 25 '21 at 19:42
  • 2
    use "self" instead of nowUTC else no sense of creating the extension function – Tanay Mondal Apr 23 '21 at 09:33
  • @MarkBrittingham Be aware that this is the worst thing you can do when dealing with dates. There is a calendar method called dateComponents in timezone exactly for this purpose. [func dateComponents(in: TimeZone, from: Date) -> DateComponents](https://developer.apple.com/documentation/foundation/calendar/2293477-datecomponents) – Leo Dabus Oct 05 '22 at 01:06
  • If I want to know how a "single point in time" maps to the current timezone, why would this be "the worst thing I can do"? Are you saying that there is a better way to use timezone? If so, can you provide an example? – Mark Brittingham Oct 05 '22 at 01:10
  • Date is just a point in time regardless of timezones. Timezone is just a representation of a date. If you need to know if "a place is open" in a different timezone you should use that method I have mentioned at my last comment. If you don't understand how you would use it feel free to open a new question describing your problem and post the link here if you would like me to take a look at it. – Leo Dabus Oct 05 '22 at 01:13
  • @MarkBrittingham Not sure if thats what you are trying to do but this might help https://stackoverflow.com/a/62590112/2303865 and this https://stackoverflow.com/a/46660225/2303865 – Leo Dabus Oct 05 '22 at 01:25
10

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
ScottyBlades
  • 12,189
  • 5
  • 77
  • 85
8

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
vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
6

I already found the answer.

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
let dateInFormat = dateFormatter.stringFromDate(NSDate())
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Nurdin
  • 23,382
  • 43
  • 130
  • 308
6

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).

trndjc
  • 11,654
  • 3
  • 38
  • 51
5
let expiryDate: Date = ...
let localizedDateString = DateFormatter.localizedString(from: expiryDate, dateStyle: .medium, timeStyle: .short)

"10 Sep 2017, 14:37"

Warif Akhand Rishi
  • 23,920
  • 8
  • 80
  • 107
4

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
Zgpeace
  • 3,927
  • 33
  • 31
2

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)
Hani Ibrahim
  • 1,448
  • 11
  • 21
0

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
Awais Fayyaz
  • 2,275
  • 1
  • 22
  • 45
Ganesh Manickam
  • 2,113
  • 3
  • 20
  • 28
-1

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
David.Chu.ca
  • 37,408
  • 63
  • 148
  • 190