I want to create a date variable but get the following response:
_startDate Date <unavailable; try printing with "vo" or "po">
The code i have is:
func createMileagesPDF() {
var _someDate: NSDate = NSDate()
self.someDate = Date()
guard (!exportYear.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && exportYear.count == 4) && cars.count > 0 else {
showAlert.toggle()
return
}
let _dateFormatter = DateFormatter()
//_dateFormatter.dateFormat = "dd-MM-yyyy"
let _startDateString = String(format: "01-01-%#", exportYear)
let _startDate = createdate() // = _dateFormatter.date(from: "01-12-2020 00:00:01")
let _x = createdate()
print("Create PDF")
}
func createdate() -> Date {
return Date()
}
What i want is an startdate based on an given year.
A string converted to an date.
When i do this in PlayGround it all works fine.
Thanks.
Related
I fail getting 'start' value, tested many variants and formatters. For production reasons cannot use ISO8601DateFormatter.
this code is part of creating appointment on the calendar, so I need start as start date/hour of the appointment.
Above all, I need to understand why this last line of code fails after I tried to convert date:
event.startDate is my 'start' but cannot set it since fails converting date
guard let url = URL(string: "calshow:\(event.startDate.timeIntervalSinceReferenceDate)") else { return }
DispatchQueue.main.async {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
my code:
date0
is a Date I get from API, with value 2021-07-28 00:00:00 +0000
my updated code for creating event on calendar
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss"
let date = dateFormatter.string(from: date0)
if let startTime = hours.from,
let startDate = date.concats(startTime),
let start = self.shortTimeFormatter.date(from: startDate) {
event.startDate = start
event.addAlarm(EKAlarm(absoluteDate: start.dayBefore))
event.addAlarm(EKAlarm(absoluteDate: start.halfHourBefore))
event.endDate = start.hourAfter
}
if let endTime = hours.to,
let endDate = date.concats(endTime),
let end = self.shortTimeFormatter.date(from: endDate) {
event.endDate = end
}
concats code
func concats(_ string: String, withSeparator separator: String? = "") -> String? {
return [self, string].compactMap{ $0 }.joined(separator: separator! + " ")
}
ShortDateTimeFormatter
public class ShortDateTimeFormatter: DateFormatter {
override public init() {
super.init()
self.dateFormat = "dd/MM/yyyy HH:mm"
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
If I understand the code you get a Date without the time portion and you want to add the time in string format "HH:mm:ss".
Calendar can do that. You don't need to convert the Date to String and back to Date.
First create a function which converts the time string to Int components
func timeComponents(from string: String) -> (Int, Int, Int)? {
let comps = string.components(separatedBy: ":")
guard comps.count == 3,
let hr = Int(comps[0]),
let mn = Int(comps[1]),
let sc = Int(comps[2])
else { return nil }
return (hr, mn, sc)
}
Then add the time to date0 with date(bySettingHour:minute:second:of:)
if let (hr, mn, sc) = timeComponents(from: "08:30:00") {
let startDate = Calendar.current.date(bySettingHour: hr, minute: mn, second: sc, of: date0)
}
Or with DateComponents
func timeComponents(from string: String) -> DateComponents? {
let comps = string.components(separatedBy: ":")
guard comps.count == 3,
let hr = Int(comps[0]),
let mn = Int(comps[1]),
let sc = Int(comps[2])
else { return nil }
return DateComponents(hour: hr, minute: mn, second: sc)
}
if let components = timeComponents(from: "08:30:00") {
let startDate = Calendar.current.date(byAdding: components, to: date0, wrappingComponents: false)
}
error: Segmentation fault: 11 (in target 'ProjectName' from project 'ProjectName')
Command CompileSwift failed with a nonzero exit code
Both of these errors are present when the following file is in my project:
import Foundation
import SwiftUI
import Mapbox
class TimeFetcher: ObservableObject {
#Published var startTime: String = ""
#Published var endTime: String = ""
#Published var eventdate: String = ""
#Published var annotation: MGLAnnotation?
#Published var eventdate: String = ""
#Published var date: Date? = Date()
#Published var startTimeDateObject: Date? = Date()
#Published var endTimeDateObject: Date? = Date()
var data: DataFetcher
var inputDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" // <- do not escape `Z` (time zone)
return formatter
}()
var outputDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.setLocalizedDateFormatFromTemplate("EEEE MMMM yyyy d") //hh mm")
return formatter
}()
var outputTimeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.setLocalizedDateFormatFromTemplate("hh mm")
return formatter
}()
var formattedDate: String {
date != nil ? self.outputDateFormatter.string(from: date!) : "Date is nil"
}
var formattedStartTime: String {
startTimeDateObject != nil ? self.outputTimeFormatter.string(from: startTimeDateObject!) : "Date is nil"
}
var formattedEndTime: String {
endTimeDateObject != nil ? self.outputTimeFormatter.string(from: endTimeDateObject!) : "Time is nil"
}
func setStartAndEndTimes() {
for event in self.data.events {
print("the selectedannotation title is \(annotation.title) and the event address is \(annotation.address)")
if self.annotation.title == event.address {
print("the start time is initially \(self.startTime)")
self.startTime = event.start_time
print("the start time at the end is \(self.startTime)")
self.endTime = event.end_time
}
}
}
func parseDate() {
let dateStr = self.eventdate
if let date = self.inputDateFormatter.date(from: dateStr) {
self.date = date
} else {
print("invalid date")
}
// alternatively if you don't care about errors:
// date = Self.dateFormatter.date(from: dateStr)
}
func parseStartTime() {
let dateStr = self.startTime
if let date = self.inputDateFormatter.date(from: dateStr) {
self.startTimeDateObject = date
} else {
print("invalid date")
}
// alternatively if you don't care about errors:
// date = Self.dateFormatter.date(from: dateStr)
}
func parseEndTime() {
let dateStr = self.endTime
if let date = self.inputDateFormatter.date(from: dateStr) {
self.endTimeDateObject = date
} else {
print("invalid date")
}
// alternatively if you don't care about errors:
// date = Self.dateFormatter.date(from: dateStr)
}
}
Also when I declare the object in my content view init, I get a weird error where it says 'TimeFetcher' cannot be constructed because it has no accessible initializers'
init() {
let vm = ViewModel()
VModel = vm
annotationsVM = AnnotationsVM(VModel: vm)
locationManager = LocationManager()
data = DataFetcher()
timeData = TimeFetcher(data: data)
}
#State and #ObservedObject should only be in a View
https://developer.apple.com/documentation/swiftui/state
https://developer.apple.com/documentation/swiftui/observedobject
Stick with #Published for all the #State and remove the #ObservedObject you don't need it in a non-View class.
I am writing code to check whether the credit card has expired or not.
Here is what I have
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yyyy"
let enteredDate = dateFormatter.date(from: expiryDate.text!) /* line 3 - set to first day of month */
let now = Date()
if (enteredDate! < now) {
//expired
// does not work if current month and year
// is the same as the expiration date,
// because expiration day is set to the first day of the month on line 3
} else {
// valid
print("valid - now: \(now) entered: \(enteredDate)")
}
Any ideas on how I can change the initialized date to be the last day of the month instead of the first day?
enteredDate will be midnight local time on the first of the month of the expiry date. Since you want that whole month to be valid, add 1 month to that value and then compare Date() to that updated value.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yyyy"
let enteredDate = dateFormatter.date(from: expiryDate.text!)!
let endOfMonth = Calendar.current.date(byAdding: .month, value: 1, to: enteredDate)!
let now = Date()
if (endOfMonth < now) {
print("Expired - \(enteredDate) - \(endOfMonth)")
} else {
// valid
print("valid - now: \(now) entered: \(enteredDate)")
}
Please note that I left proper handling of optionals as an exercise for the reader.
Instead of comparing the dates, compare month of the dates using compare(_:to:toGranularity:)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yyyy"
if let enteredDate = dateFormatter.date(from: "05/2019") {
let result = Calendar.current.compare(Date(), to: enteredDate, toGranularity: .month)
if result == .orderedSame {
print("valid")
} else if result == .orderedAscending {
print("valid")
} else if result == .orderedDescending {
print("expired")
}
}
rmaddy's answer is perfect. Here is how I thought of using Calendar to handle the validation. Perhaps, I wrote it in more complex way.
enum ExpiryValidation {
case valid, invalidInput, expired
}
func validateCreditCardExpiry(_ input: String) -> ExpiryValidation {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yyyy"
guard let enteredDate = dateFormatter.date(from: input) else {
return .invalidInput
}
let calendar = Calendar.current
let components = Set([Calendar.Component.month, Calendar.Component.year])
let currentDateComponents = calendar.dateComponents(components, from: Date())
let enteredDateComponents = calendar.dateComponents(components, from: enteredDate)
guard let eMonth = enteredDateComponents.month, let eYear = enteredDateComponents.year, let cMonth = currentDateComponents.month, let cYear = currentDateComponents.year, eMonth >= cMonth, eYear >= cYear else {
return .expired
}
return .valid
}
let invalidInput = validateCreditCardExpiry("hello")
let validInput = validateCreditCardExpiry("09/2020")
let expiredInput = validateCreditCardExpiry("04/2010")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yyyy"
let enteredDate = dateFormatter.date(from: expiryDate.text!)
//Also convert the current date in the entered date format and then checks that the date is valid if enteredDate month or year is greater than current date.
let currentDate = dateFormatter.date(from: dateFormatter.string(from: Date()))
if enteredDate.compare(now) != ComparisonResult.orderedAscending {
print("Valid")
} else {
print("Not Valid")
}
As this only compares the month and year so it will resolve your issue of first or last date of month.
Here is the full answer for Expiry date calculation from textfield formatted as MM/YY. Use this in textfieldshouldchangecharactersinrange method
var cleanString = string.replacingOccurrences(of: "/", with: "")
if cleanString.rangeOfCharacter(from: unsupportedCharacterSet) != nil {
return ""
}
let dateString: String
if cleanString.count == 0 {
return string
} else if cleanString.count > 4 {
// trim the string down to 4
let reqIndex = cleanString.index(cleanString.startIndex, offsetBy: 4)
cleanString = String(cleanString[..<reqIndex])
}
if cleanString.hasPrefix("0") == false && cleanString.hasPrefix("1") == false {
dateString = "0" + cleanString
} else {
dateString = cleanString
}
let currentYear = Calendar.current.component(.year, from: Date()) % 100 // This will give you current year (i.e. if 2019 then it will be 19)
let currentMonth = Calendar.current.component(.month, from: Date()) // This will give you current month (i.e if June then it will be 6)
var newText = ""
for (index, character) in dateString.enumerated() {
print("index: \(index)")
if index == 1 {
let enterdMonth = Int(dateString.prefix(2)) ?? 0 // get first two digit from entered string as month
print("enterdMonth at 1:\(enterdMonth)")
if (1 ... 12).contains(enterdMonth){
if enterdMonth < 10 {
newText = "0" + "\(enterdMonth)" + "/"
}else {
newText = "\(enterdMonth)" + "/"
}
}else{
}
}else if index == 2 {
if (2 ... 99).contains(Int(String(character))!) { // Entered year should be greater than 2019.
newText.append(character)
}else{
}
}else if index == 3 {
print("index---: \(index)")
let enterdYr = Int(dateString.suffix(2)) ?? 0 // get last two digit from entered string as year
let enterdMonth = Int(dateString.prefix(2)) ?? 0 // get first two digit from entered string as month
print("enterdYr: \(enterdYr)")
print("currentYear: \(currentYear)")
if (2 ... 99).contains(enterdYr) { // Entered year should be greater than 2019
if enterdYr >= currentYear {
if (1 ... 12).contains(enterdMonth) {
if enterdMonth < 10 {
newText = "0" + "\(enterdMonth)" + "/" + "\(enterdYr)"
}else {
newText = "\(enterdMonth)" + "/" + "\(enterdYr)"
}
return newText
}
}
}
}
else {
newText.append(character)
}
}
return newText
}
if enteredDate.compare(now) == ComparisonResult.orderedDescending
{
print("valid")
}
else{
print("not valid")
}
I am trying to convert the timestamp from server and it is converting also but only month is coming wrong.Like timestamp is 1492747393892 and it convert into 21/03/17 - 12:03PM but it should be 21/04/17 - 12:03PM.
Here is my code
var arriveTimestamp: Int
if let timeStampToDate = arriveTimestamp {
let timeSt = Date(jsonTimeDate:"/Date(\(timeStampToDate))/")
let time = Date().dateTime(date: timeSt!)
valueLbl.text = time
}
init?(jsonTimeDate: String) {
// "/Date(1487058855745)/"
let prefix = "/Date("
let suffix = ")/"
let scanner = Scanner(string: jsonTimeDate)
// Check prefix:
guard scanner.scanString(prefix, into: nil) else { return nil }
// Read milliseconds part:
var milliseconds : Int64 = 0
guard scanner.scanInt64(&milliseconds) else { return nil }
// Milliseconds to seconds:
var timeStamp = TimeInterval(milliseconds)/1000.0
// Read optional timezone part:
var timeZoneOffset : Int = 0
if scanner.scanInt(&timeZoneOffset) {
let hours = timeZoneOffset / 100
let minutes = timeZoneOffset % 100
// Adjust timestamp according to timezone:
timeStamp += TimeInterval(3600 * hours + 60 * minutes)
}
// Check suffix:
guard scanner.scanString(suffix, into: nil) else { return nil }
// Success! Create NSDate and return.
self.init(timeIntervalSince1970: timeStamp)
}
func dateTime(date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/mm/yy - hh:mm a"
return dateFormatter.string(from: date as Date)
}
The main error in your code is the wrong date format for the month,
which should be "MM", not "mm" (which is for the minutes).
Apart from that, your approach is far too complicated. All you have to
do is to divide the timestamp (which is in milliseconds) by 1000
and call Date(timeIntervalSince1970:):
let arriveTimestamp = 1492747393892
let date = Date(timeIntervalSince1970: TimeInterval(arriveTimestamp)/1000)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yy - hh:mm a"
let text = dateFormatter.string(from: date)
print(text) // 21/04/17 - 06:03 AM
I have a String in following format
"/Date(573465600000-0800)/"
How do I convert this to regular NSDate object?
The first part "573465600000" is the time since the Unix epoch
in milliseconds, and the second part "-0800" is a time zone
specification.
Here is a slight modification of Parsing JSON (date) to Swift
which also covers the time zone part:
extension NSDate {
convenience init?(jsonDate: String) {
let prefix = "/Date("
let suffix = ")/"
let scanner = NSScanner(string: jsonDate)
// Check prefix:
if scanner.scanString(prefix, intoString: nil) {
// Read milliseconds part:
var milliseconds : Int64 = 0
if scanner.scanLongLong(&milliseconds) {
// Milliseconds to seconds:
var timeStamp = NSTimeInterval(milliseconds)/1000.0
// Read optional timezone part:
var timeZoneOffset : Int = 0
if scanner.scanInteger(&timeZoneOffset) {
let hours = timeZoneOffset / 100
let minutes = timeZoneOffset % 100
// Adjust timestamp according to timezone:
timeStamp += NSTimeInterval(3600 * hours + 60 * minutes)
}
// Check suffix:
if scanner.scanString(suffix, intoString: nil) {
// Success! Create NSDate and return.
self.init(timeIntervalSince1970: timeStamp)
return
}
}
}
// Wrong format, return nil. (The compiler requires us to
// do an initialization first.)
self.init(timeIntervalSince1970: 0)
return nil
}
}
Example:
if let theDate = NSDate(jsonDate: "/Date(573465600000-0800)/") {
println(theDate)
} else {
println("wrong format")
}
Output:
1988-03-04 00:00:00 +0000
Update for Swift 3 (Xcode 8):
extension Date {
init?(jsonDate: String) {
let prefix = "/Date("
let suffix = ")/"
let scanner = Scanner(string: jsonDate)
// Check prefix:
guard scanner.scanString(prefix, into: nil) else { return nil }
// Read milliseconds part:
var milliseconds : Int64 = 0
guard scanner.scanInt64(&milliseconds) else { return nil }
// Milliseconds to seconds:
var timeStamp = TimeInterval(milliseconds)/1000.0
// Read optional timezone part:
var timeZoneOffset : Int = 0
if scanner.scanInt(&timeZoneOffset) {
let hours = timeZoneOffset / 100
let minutes = timeZoneOffset % 100
// Adjust timestamp according to timezone:
timeStamp += TimeInterval(3600 * hours + 60 * minutes)
}
// Check suffix:
guard scanner.scanString(suffix, into: nil) else { return nil }
// Success! Create NSDate and return.
self.init(timeIntervalSince1970: timeStamp)
}
}
Example:
if let theDate = Date(jsonDate: "/Date(573465600000-0800)/") {
print(theDate)
} else {
print("wrong format")
}
var date:NSDate = NSDate(timeIntervalSince1970: timeInterval)
let myTimeStamp = "1463689800000.0"
let dateTimeStamp = NSDate(timeIntervalSince1970:Double(myTimeStamp)!/1000) //UTC time
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone() //Edit
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.dateStyle = NSDateFormatterStyle.FullStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
let strDateSelect = dateFormatter.stringFromDate(dateTimeStamp)
print(strDateSelect) //Local time
let dateFormatter2 = NSDateFormatter()
dateFormatter2.timeZone = NSTimeZone.localTimeZone()
dateFormatter2.dateFormat = "yyyy-MM-dd"
let date3 = dateFormatter.dateFromString(strDateSelect)
datepicker.date = date3!
Swift 4
let date = Date(timeIntervalSince1970: TimeInterval(1463689800000.0))