I'm pretty new to swift (and programming altogether). I'm trying to convert an Int into a String. I've tried using switch statements but every time I use them, it never changes to the String (AKA it prints the number 4) An example of what I'm trying to do is as follows:
class Birthday(_ month: Int, _ day:Int, _ year:Int) -> String{
//Here is where I'd like to turn my month into April
Return (month)
}
let example = Birthday()
example(4,15,1988)
If you really just want to get a month name from a month number, you can do the following:
let formatter = DateFormatter()
let monthName = formatter.monthSymbols[month - 1] // Assuming 1 means January
But since you are passing in a month, day, and year, you presumably want to create a Date and then you want to format that Date into a `String.
Create a Date using Calendar and DateComponents.
let date = Calendar.current.date(from: DateComponents(year: year, month: month, day: day))
Then you format the Date into a String using DateFormatter.
let formatter = DateFormatter()
formatter.dateStyle = .long // choose a desired style
formatter.timeStyle = .none
let string = formatter.string(from: date)
You can use a dictionary which maps objects to each other. For example, a months dictionary could look like:
let months: [Int:String] = [1:"January", 2:"February",...]
return months[4] // returns "April"
Simple solution to get you started would be a method that takes an integer and return your month string.
func numberToMonth(number: Int) -> String {
guard number > 0, number < 13 else { return "" }
return DateFormatter().monthSymbols[number-1]
}
Related
I have a date in string format, "yyyy-MM-dd" and would like to return an array of the difference in dates in that same format from today.
For example, the given date is "2019-06-29", and today's date is 2019-06-25. The returned array would contain: ["2019-06-25", "2019-06-26", "2019-06-27", "2019-06-28", "2019-06-29"].
The method I am trying to write needs to also work cross-months/years. Is something like this possible in Swift?
What I have tried: calculating the difference in dates numerically (difference of days) and adding a day to the given date until it reaches today's date. This is what brought on the issue of exceeding 30/31 days and not moving to the next months/exceeding 2019-12-31 and not moving to 2020. Surely there is a simpler concise way to achieve this result without having to write that date logic manually?
extension Formatter {
static let date: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter
}()
}
extension Date {
var noon: Date {
return Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
}
}
func dates(for date: String) -> [String] {
// For calendrical calculations you should use noon time
// So lets get endDate's noon time
guard let endDate = Formatter.date.date(from: date)?.noon else { return [] }
// then lets get today's noon time
var date = Date().noon
var dates: [String] = []
// while date is less than or equal to endDate
while date <= endDate {
// add the formatted date to the array
dates.append( Formatter.date.string(from: date))
// increment the date by one day
date = Calendar.current.date(byAdding: .day, value: 1, to: date)!
}
return dates
}
dates(for: "2019-06-29") // ["2019-06-25", "2019-06-26", "2019-06-27", "2019-06-28", "2019-06-29"]
How can I just remove the year when using the DateFormatter Full Style. I would like it to display the date like this, ex:( Thursday, October 4). Excluding the year.
Currently I have:
func todaysDate() {
dateLabel.text = DateFormatter.localizedString(from: NSDate() as Date, dateStyle: DateFormatter.Style.full, timeStyle: DateFormatter.Style.none)
}
If you want a properly localized but custom format, you need to use setLocalizedDateFormatFromTemplate.
func todaysDate() {
let df = DateFormatter()
df.setLocalizedDateFormatFromTemplate("EEEEMMMMd")
dateLabel.text = df.string(from: Date())
}
EEEE gives the full weekday name. MMMM gives the full month name. d gives the day of the month.
Based on the user's locale, the resulting format will be in the correct order with appropriate punctuation added.
Also note there is no reason to use NSDate.
As a side note, I would refactor your code to be more like this:
func todaysDate() -> String {
let df = DateFormatter()
df.setLocalizedDateFormatFromTemplate("EEEEMMMMd")
return df.string(from: Date())
}
And then where you are currently calling:
todaysDate()
I would do:
dateLabel.text = todaysDate()
I have an ISO-8601 date string like this: "2017-02-07T00:00:00-08:00".
How can I extract the TimeZone object from this date?
Unfortunately, DateFormatter is no help since you don't want a Date nor does it provide any information about any timezone info about a parsed date string. And TimeZone doesn't have any initializer that can parse a timezone offset string.
So you will have to do the work yourself. Since you have a fixed format date string, you know the timezone offset is always going to be the last 6 characters of the string. The last 2 of those are the number of minutes and the first 3 of those are the number of hours (including the sign).
Extract these two substrings (hours and minutes) from the date string. Convert them both to Int. Then do some simple math to calculate an offset in seconds (hours * 3600 + minutes * 60).
Once you have that offset in seconds, you can create a TimeZone instance using the init(secondsFromGMT:) initializer.
Using rmaddys proposed solution, I wrote an extension for TimeZone which should do the job.
extension TimeZone {
init?(iso8601String: String) {
let timeZoneString = String(iso8601String.suffix(6))
let sign = String(timeZoneString.prefix(1))
guard sign == "+" || sign == "-" else {
return nil
}
let fullTimeString = timeZoneString.filter("0123456789".contains)
guard fullTimeString.count == 4 else {
return nil
}
guard let hours = Int(sign+fullTimeString.prefix(2)), let minutes = Int(sign+fullTimeString.suffix(2)) else {
return nil
}
let secondsFromGMT = hours * 3600 + minutes * 60
self.init(secondsFromGMT: secondsFromGMT)
}
}
You could create a date formatter that only returns the time zone such as below. Change the abbreviation to whichever time zone you are looking for.
let timeZoneOnlyDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.dateStyle = .none
formatter.timeStyle = .none
return formatter
}()
And use these functions to convert it to a string or convert your string to a date.
func formatDateIntoString(date: Date, dateFormatter: DateFormatter) -> String {
return dateFormatter.string(from: date)
}
func formatStringIntoDate(string: String, dateFormatter: DateFormatter) -> Date! {
return dateFormatter.date(from: string)
}
I am updating some of my old Swift 2 answers to Swift 3. My answer to this question, though, is not easy to update since the question specifically asks for NSDate and not Date. So I am creating a new version of that question that I can update my answer for.
Question
If I start with a Date instance like this
let someDate = Date()
how would I convert that to an integer?
Related but different
These questions are asking different things:
Swift convert unix time to date and time
Converting Date Components (Integer) to String
Convert Date String to Int Swift
Date to Int
// using current date and time as an example
let someDate = Date()
// convert Date to TimeInterval (typealias for Double)
let timeInterval = someDate.timeIntervalSince1970
// convert to Integer
let myInt = Int(timeInterval)
Doing the Double to Int conversion causes the milliseconds to be lost. If you need the milliseconds then multiply by 1000 before converting to Int.
Int to Date
Including the reverse for completeness.
// convert Int to TimeInterval (typealias for Double)
let timeInterval = TimeInterval(myInt)
// create NSDate from Double (NSTimeInterval)
let myNSDate = Date(timeIntervalSince1970: timeInterval)
I could have also used `timeIntervalSinceReferenceDate` instead of `timeIntervalSince1970` as long as I was consistent. This is assuming that the time interval is in seconds. Note that Java uses milliseconds.
Note
For the old Swift 2 syntax with NSDate, see this answer.
If you are looking for timestamp with 10 Digit seconds since 1970 for API call then, below is code:
Just 1 line code for Swift 4/ Swift 5
let timeStamp = UInt64(Date().timeIntervalSince1970)
print(timeStamp) <-- prints current time stamp
1587473264
let timeStamp = UInt64((Date().timeIntervalSince1970) * 1000) // will give 13 digit timestamp in milli seconds
timeIntervalSince1970 is a relevant start time, convenient and provided by Apple.
If u want the int value to be smaller, u could choose the relevant start time you like
extension Date{
var intVal: Int?{
if let d = Date.coordinate{
let inteval = Date().timeIntervalSince(d)
return Int(inteval)
}
return nil
}
// today's time is close to `2020-04-17 05:06:06`
static let coordinate: Date? = {
let dateFormatCoordinate = DateFormatter()
dateFormatCoordinate.dateFormat = "yyyy-MM-dd HH:mm:ss"
if let d = dateFormatCoordinate.date(from: "2020-04-17 05:06:06") {
return d
}
return nil
}()
}
extension Int{
var dateVal: Date?{
// convert Int to Double
let interval = Double(self)
if let d = Date.coordinate{
return Date(timeInterval: interval, since: d)
}
return nil
}
}
Use like this:
let d = Date()
print(d)
// date to integer, you need to unwrap the optional
print(d.intVal)
// integer to date
print(d.intVal?.dateVal)
I'm trying to display the time of something being open based on what day it is. Something like this:
Opening Hours
**Monday: 8:00-17:00**
Tuesday: 8:00-17:00
Wednesday: 8:00-17:00
Thursday: 8:00-17:00
Friday: 8:00-17:00
Saturday: 8:00-13:00
Sunday: closed
Or simply display
Monday: 8:00-17:00
My assumption would be to use switch statements, but what would I need to do to find out what day it is?
Another solution could be:
import Foundation
let today = NSDate()
let dateFormatter = NSDateFormatter()
let currentDay = NSCalendar.currentCalendar().component(.Weekday, fromDate:today);
dateFormatter.dateFormat = "EEEE"
let dayOfWeekString = dateFormatter.stringFromDate(today)
switch currentDay
{
case 2,3,4,5:
print("\(dayOfWeekString): 8:00 - 17:00")
case 6:
print("\(dayOfWeekString): 8:00 - 13:00")
default:
print("\(dayOfWeekString): closed")
}
You can use component(_:fromDate:) to get the week day from the current date. That would look like:
let currentDay = NSCalendar.currentCalendar().component(.Weekday, fromDate:NSDate());
Based on the value you get for currentDay, you can provide the correct opening hours.
You can make use of NSCalendar to get the .Weekday unit as an integer (Sunday through Saturday as 1 ... 7 for the Gregorian calendar).
Given you know the day of the week represented as an Int, rather than using a switch statement, you could use a [Int: String] dictionary for the different opening hours.
let calendar = NSCalendar.currentCalendar()
let today = calendar.component(.Weekday, fromDate: NSDate())
// Gregorian calendar: sunday = 0, monday = 1, ...
let openingHours: [Int: String] = [1: "Sunday: closed", 2: "Monday: 8:00-17:00", 3: "Tuesday: 8:00-17:00"] // ...
print("Opening hours:\n\(openingHours[today] ?? "")")
/* Opening hours:
Monday: 8:00-17:00 */
Another alternative is to create a computed property extension to NSDate() that returns the current weekday as a String
extension NSDate {
var weekday : String {
let formatter = NSDateFormatter()
formatter.dateFormat = "EEEE"
return formatter.stringFromDate(self)
}
}
This can be readily used with a [String: String] dictionary for holding the set of weekday : opening hours:
/* example usage */
let openingHours: [String: String] =
["Sunday": "closed",
"Monday": "8:00-17:00",
"Tuesday": "8:00-17:00"] // ...
let today = NSDate().weekday
print("Opening hours:\n\(today): \(openingHours[today] ?? "")")
/* Opening hours:
Monday: 8:00-17:00 */
Rather than going with switch statements I would prefer a more generic solution. This is also a nice demonstration of leveraging tuples and type aliases for enhancing code expressiveness and readability.
typealias Time = (start: Int, end: Int)
// starting with Sunday
let openTimes: [Time] = [(0,0), (9,17), (9,17), (9,17), (9,17), (9,17), (9,12)]
let flags : NSCalendarUnit = [.Hour, .Weekday]
func isOpenAtTime(date: NSDate) -> Bool {
let time = NSCalendar.currentCalendar().components(flags, fromDate: date)
let openingHours = openTimes[time.weekday - 1]
let hour = time.hour
return hour >= openingHours.start && hour <= openingHours.end
}
You might want to handle a few edge cases as well, but you get the idea.
You could make this work with more granular time by using minutes instead of hours.