Swift 4:验证信用卡到期日期

Posted

技术标签:

【中文标题】Swift 4:验证信用卡到期日期【英文标题】:Swift 4: validating credit card expiration date 【发布时间】:2021-12-24 11:14:14 【问题描述】:

我正在编写代码来检查信用卡是否已过期。

这就是我所拥有的

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

关于如何将初始化日期更改为当月的最后一天而不是第一天的任何想法?

【问题讨论】:

您可以对 Date 使用比较方法而不是 , == 你能举个例子吗? 也许,您可以使用 Calendar 和组件月份和年份。这样比较容易。 【参考方案1】:

这是从格式为 MM/YY 的文本字段计算到期日期的完整答案。在 textfieldshouldchangecharactersinrange 方法中使用这个

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

【讨论】:

【参考方案2】:

不是比较日期,而是使用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")
    

【讨论】:

【参考方案3】:
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")

由于这仅比较月份和年份,因此它将解决您的第一个或最后一个日期的问题。

【讨论】:

【参考方案4】:

enteredDate 将是到期日期当月第一天的当地时间午夜。由于您希望整个月份都有效,因此将 1 个月添加到该值,然后将 Date() 与更新后的值进行比较。

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

请注意,我将正确处理选项作为练习留给读者。

【讨论】:

如果它处理的是日组件而不是月,这会起作用吗? & 它适用于不同的时区吗?【参考方案5】:

rmaddy's 答案很完美。这是我想到使用Calendar 处理验证的方式。也许,我用更复杂的方式写了它。

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

【讨论】:

请注意,强制解开 currentDateComponentsenteredDateComponents 上的 monthyear 属性是完全安全的,因为您特别要求这些值。他们不会是nil 是的,我知道。以这种方式使用它已经成为一种习惯。【参考方案6】:
if enteredDate.compare(now) == ComparisonResult.orderedDescending
        
            print("valid")
        
else
      print("not valid")

【讨论】:

以上是关于Swift 4:验证信用卡到期日期的主要内容,如果未能解决你的问题,请参考以下文章

信用卡到期日自动填充 - 如何使用 4 位数年份?

我只需要存储信用卡的最后 4 位数字

存储信用卡信息

有没有办法验证、存储和检索信用卡信息?

Authorize.net:如何使用“AUTH_ONLY”验证信用卡?

信用卡到期的正则表达式