Not able to get date based on current locale - ios

I’m populating month and date in a tableview. I have the app supporting France language also along with English. But I’m not able to get the months in France language when I change the locale to French. It’s getting reflected only once I launch the app again and not immediately after I change the language within the app.
This is what I have tried in cellForRowAtIndexPath…
let dic = myArray[indexPath.row] as! NSMutableDictionary
var utcTime = "\(dic["Due_Date"]!)"
self.dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss”
let currentLanguage = …. (Correctly gives ‘en’ OR ‘fr')
self.dateFormatter.locale = Locale.init(identifier: currentLanguage)
self.dateFormatter.timeZone = TimeZone(abbreviation: "UTC”)
if let date = dateFormatter.date(from:utcTime) {
let monthInt = Calendar.current.component(.month, from: date)
dayInt = Calendar.current.component(.day, from: date)
let yearInt = Calendar.current.component(.year, from: date)
let monthStr = Calendar.current.monthSymbols[monthInt-1]
print(monthStr, dayInt). //If the current language is ‘fr’ the month is printed here in English. It changes back to French only after I launch the app again
}
EDIT: This is how I changed the language within the app..
There is a class like so...
let APPLE_LANGUAGE_KEY = "AppleLanguages"
class TheLanguage {
class func currentAppleLanguage() -> String{
let userdef = UserDefaults.standard
let langArray = userdef.object(forKey: APPLE_LANGUAGE_KEY) as! NSArray
let current = langArray.firstObject as! String
return current
}
class func setAppleLAnguageTo(lang: String) {
let userdef = UserDefaults.standard
userdef.set([lang,currentAppleLanguage()], forKey: APPLE_LANGUAGE_KEY)
userdef.synchronize()
}
}
And I get the current language like so...
let currentLanguage = TheLanguage.currentAppleLanguage()

From the docs:
monthSymbols:
A list of months in this calendar, localized to the Calendar’s locale.
So I guess you need to change the calendar's locale to the one the user has selected.
Edit:
But, if you just need the month name from a given date (don't known what type dueDate is in your example) you can use this code:
let dueDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "LLLL"
dateFormatter.locale = Locale(identifier: "fr")
let month = dateFormatter.string(from: dueDate)

Related

Date component hour is different from what I set it up as in Swift [duplicate]

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

Compare date components Swift

I have a task where I have to read the file once a day.
1)Label with text and the date blank.
2)When the user first goes to view. I need to show the text, save it and the date when it was followed
3)Leave it all on the screen all day.
4)When the next day comes. Compare the saved date with the current date.
5)If the current date is greater than the stored date. then read the file again, show the text and the date when this is done and save
(While there is this. The text changes every time you enter the application.
A saved date = 0,)
// compare oderDate and currentDate
func showTextToDay() {
let newDatePredict = Date()
let olderDate = UserDefaults.standard.object(forKey: dateUser) as! Date // THIS PROBLEM
let order = Calendar.current.compare(olderDate, to: newDatePredict, toGranularity: .day)
switch order {
case .orderedDescending:
print("DESCENDING")
case .orderedAscending:
readFilePrediction() //read again file bcs new day
print("ASCENDING")
case .orderedSame:
print("SAME")
}
}
func readFilePrediction() {
//some code
}
// save olderDate Func
func saveDatePredictFunc() {
let oldDatePredict = Date()
UserDefaults.standard.set(oldDatePredict, forKey: dateUser)
let dateLabel = UserDefaults.standard.object(forKey: dateUser) as! Date
let df = DateFormatter()
df.dateFormat = "dd/MM/yyyy"
toDateOutlet.text = df.string(from: dateLabel)
defaults.set(toDateOutlet.text, forKey: dateUser)
}
You have to check also if a date a available at all.
The guard statement represents a NOR expression. readFilePrediction will be executed if the date does NOT exist OR the date comparison is ascending.
func showTextToDay()
{
guard let olderDate = UserDefaults.standard.object(forKey: dateUser) as? Date,
Calendar.current.compare(olderDate, to: Date(), toGranularity: .day) != .orderedAscending else {
readFilePrediction()
saveDatePredictFunc()
return
}
}
And reading the data right after saving it to UserDefaults (dateLabel) is very bad practice. You got the value. And delete also the line to save the string representation of the date. The line breaks the ability to read the value as Date.
func saveDatePredictFunc()
{
let oldDatePredict = Date()
UserDefaults.standard.set(oldDatePredict, forKey: dateUser)
let df = DateFormatter()
df.dateFormat = "dd/MM/yyyy"
toDateOutlet.text = df.string(from: oldDatePredict)
}

How to display Localized days of the week in CollectionView in Swift? iOS

I was just making a weather app that displays 5-day weather temperatures. And the problem that I have right now is how do I display weekdays that are retrieved dynamically on my Collection View? They are well displaying in English, but I want them to be in Russian. The source is given below:
This is the code that is in my cellForItemAt function
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.setLocalizedDateFormatFromTemplate("EEEE")
let actualDate = dateFormatter.string(from: date)
cell.dayCollection.text = String(NSLocalizedString("%#", comment: "displaying weekdays"), actualDate) // see this line
return cell
This is my Localizable.string file:
"%#" = "Воскресенье";
"%#" = "Понедельник";
"%#" = "Вторник";
"%#" = "Среда";
"%#" = "Четверг";
"%#" = "Пятница";
"%#" = "Суббота";
Please let me know if you need any other source or answer. Any help will be very appreciated!
I think it better to use the default localization for dates, instead of custom localized string.
let date = Date()
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "ru_RU")
dateFormatter.dateFormat = "EEEE"
let day = dateFormatter.string(from: date).capitalized
print(day) // you will see eg. "Пятница"
You can even you use Locale.current and days will show according to user's device language.
Your Localized.string file should be
"Sunday" = "Воскресенье";
"Monday" = "Понедельник";
"Tuesday" = "Вторник";
"Wednesday" = "Среда";
"Thursday" = "Четверг";
"Friday" = "Пятница";
"Saturday" = "Суббота";
and
let day = NSLocalizedString(actualDate, comment: "")
cell.dayCollection.text = day
Update for displaying "Today" as current day
Create Extension+Date.swift file first. Add code below into the file.
extension Date {
/// Compare self with another date.
///
/// - Parameter anotherDate: The another date to compare as Date.
/// - Returns: Returns true if is same day, otherwise false.
public func isSame(_ anotherDate: Date) -> Bool {
let calendar = Calendar.autoupdatingCurrent
let componentsSelf = calendar.dateComponents([.year, .month, .day], from: self)
let componentsAnotherDate = calendar.dateComponents([.year, .month, .day], from: anotherDate)
return componentsSelf.year == componentsAnotherDate.year && componentsSelf.month == componentsAnotherDate.month && componentsSelf.day == componentsAnotherDate.day
}
}
At your cellForRow modify to:
var actualDate = dateFormatter.string(from: date)
if date.isSame(Date()) {
actualDate = "Today"
}
Add Today key in your Localized.string file
"Today" = "Cегодня";

Get Current month & year and Passing to API iOS Swift?

I have a func in which i have to pass current month & year parameters to Fetch API in Swift 3.If i pass hardCode in parameters i am getting the son response but i am not able to do it with current month & year. Code :-
func raffleNumberGenerate(){
let prs = [
"month":currentMonth,
"year" : currentYear,
"raffle_result": "1" as String
]
Service.StartWithoutLoading(prs as [String : AnyObject]?, onCompletion: { result in
let jsonResponseSingle = result as? NSDictionary
print(" JSON Response :- \(String(describing: jsonResponseSingle))"
}
Thanks in advance.
You have no values for currentMonth and currentYear, so you must make some.
func raffleNumberGenerate() {
let date = Date() // gets current date
let calendar = Calendar.current
let currentYear = calendar.component(.year, from: date) // gets current year (i.e. 2017)
let currentMonth = calendar.component(.month, from: date) // gets current month (i.e. 10)
let prs = [
"month":currentMonth,
"year" : currentYear,
"raffle_result": "1" as String
]
Service.StartWithoutLoading(prs as [String : AnyObject]?, onCompletion: { result in
let jsonResponseSingle = result as? NSDictionary
print(" JSON Response :- \(String(describing: jsonResponseSingle))"
}
}
Now you should be able to do whatever you need to do with the JSON. I should note that currentMonth and currentYear are now of type Int, if you need them as Strings you can just convert by saying String(currentMonth) and String(currentYear).
let today = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy"
let year = dateFormatter.string(from: today)
dateFormatter.dateFormat = "MM"
let month = dateFormatter.string(from: today)
e.g. year = 2017 month = 10
per #maddy
var calendar = NSCalendar.current
let today = Date()
let desiredComponents = Set<Calendar.Component>([.month, .year])
calendar.timeZone = TimeZone(identifier: "UTC")!
let components = calendar.dateComponents(desiredComponents, from: today)
components.year
components.month

How do i get a number data and date data from parse and put it to UILabel?

Currently I want to retrieve createdAt and price from parse database and the datatypes for both are Number and NSDate. After I retrieved it I want to pass to UILabel which is date and price respectively. The problem right now is that whenever I tried to run the simulator, both of the UILabel data don't show up while string data type does show up.
My current code
if let createdAt = object?["createdAt"] as? String {
cell.date.text = createdAt
}
if let priceTitle = object?["price"] as? String {
cell.price.text = priceTitle
}
For Date, use NSDateFormatter.stringFromDate method so your code should be:
if let createdAt = object?["createdAt"] as? NSDate {
let dateFormatter = NSDateFormatter()
var theDateFormat = NSDateFormatterStyle.ShortStyle
dateFormatter.dateStyle = theDateFormat
cell.date.text = dateFormatter.stringFromDate(createdAt)
}
createdAt is a special value in Parse. It is PFObject's property and you access it with dot notation. So this is how you should proceed:
if let object = object as? PFObject {
let date = object.createdAt
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm MMMM dd, yyyy"
let dateStr = dateFormatter.stringFromDate(date!)
cell.date.text = dateStr
}

Resources