Skip to content

Commit

Permalink
Handle date parsing for 2 digits year (#140)
Browse files Browse the repository at this point in the history
Co-authored-by: Tai Pham <[email protected]>
  • Loading branch information
megaxayda and Tai Pham authored Mar 3, 2023
1 parent 7a0a584 commit e51d9e5
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import android.content.Context
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
Expand All @@ -31,6 +32,7 @@ import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import io.reactivex.disposables.CompositeDisposable
import net.sf.scuba.smartcards.CardServiceException
Expand All @@ -41,6 +43,8 @@ import org.idpass.smartscanner.lib.nfc.details.NFCDocumentTag
import org.idpass.smartscanner.lib.nfc.passport.Passport
import org.idpass.smartscanner.lib.scanner.config.Language
import org.idpass.smartscanner.lib.utils.DateUtils
import org.idpass.smartscanner.lib.utils.DateUtils.BIRTH_DATE_THRESHOLD
import org.idpass.smartscanner.lib.utils.DateUtils.EXPIRY_DATE_THRESHOLD
import org.idpass.smartscanner.lib.utils.DateUtils.formatStandardDate
import org.idpass.smartscanner.lib.utils.KeyStoreUtils
import org.idpass.smartscanner.lib.utils.LanguageUtils
Expand Down Expand Up @@ -183,15 +187,16 @@ class NFCFragment : Fragment() {
super.onDetach()
}

@RequiresApi(Build.VERSION_CODES.O)
override fun onResume() {
super.onResume()
// Display proper language
LanguageUtils.changeLanguage(requireContext(), if (language == Language.EN) Language.EN else Language.AR)
// Display MRZ details
textViewNfcTitle?.text = if (label != null) label else getString(R.string.nfc_title)
textViewPassportNumber?.text = getString(R.string.doc_number, mrzInfo?.documentNumber)
textViewDateOfBirth?.text = getString(R.string.doc_dob, DateUtils.toAdjustedDate(formatStandardDate(mrzInfo?.dateOfBirth)))
textViewDateOfExpiry?.text = getString(R.string.doc_expiry, DateUtils.toReadableDate(formatStandardDate(mrzInfo?.dateOfExpiry)))
textViewDateOfBirth?.text = getString(R.string.doc_dob, DateUtils.toAdjustedDate(formatStandardDate(mrzInfo?.dateOfBirth, threshold = BIRTH_DATE_THRESHOLD)))
textViewDateOfExpiry?.text = getString(R.string.doc_expiry, DateUtils.toReadableDate(formatStandardDate(mrzInfo?.dateOfExpiry, threshold = EXPIRY_DATE_THRESHOLD)))

if (nfcFragmentListener != null) {
nfcFragmentListener?.onEnableNfc()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
*/
package org.idpass.smartscanner.lib.nfc

import android.os.Build
import androidx.annotation.RequiresApi
import org.idpass.smartscanner.lib.nfc.passport.Passport
import org.idpass.smartscanner.lib.scanner.config.Language.Locale
import org.idpass.smartscanner.lib.utils.DateUtils
import org.idpass.smartscanner.lib.utils.DateUtils.BIRTH_DATE_THRESHOLD
import org.idpass.smartscanner.lib.utils.DateUtils.EXPIRY_DATE_THRESHOLD
import org.idpass.smartscanner.lib.utils.DateUtils.formatStandardDate
import org.idpass.smartscanner.lib.utils.LanguageUtils.isRTL
import org.idpass.smartscanner.lib.utils.extension.arrayToString
Expand Down Expand Up @@ -54,6 +58,7 @@ data class NFCResult(
) {
companion object {

@RequiresApi(Build.VERSION_CODES.O)
fun formatResult(passport: Passport?, locale: String?, mrzInfo: MRZInfo? = null, image: String? = null, mrzImage: String? = null): NFCResult {
val personDetails = passport?.personDetails
val additionalPersonDetails = passport?.additionalPersonDetails
Expand Down Expand Up @@ -102,9 +107,9 @@ data class NFCResult(
}
}
// Get proper date of birth
val dateOfBirth = if (additionalPersonDetails?.fullDateOfBirth.isNullOrEmpty()) {
DateUtils.toAdjustedDate (formatStandardDate(personDetails?.dateOfBirth))
} else formatStandardDate(additionalPersonDetails?.fullDateOfBirth, "yyyyMMdd")
val dateOfBirth = if (additionalPersonDetails?.fullDateOfBirth.isNullOrEmpty()) {
DateUtils.toAdjustedDate (formatStandardDate(personDetails?.dateOfBirth, threshold = BIRTH_DATE_THRESHOLD))
} else formatStandardDate(additionalPersonDetails?.fullDateOfBirth, "yyyyMMdd")
return NFCResult(
image = image,
mrzImage = mrzImage,
Expand All @@ -113,7 +118,7 @@ data class NFCResult(
nameOfHolder = additionalPersonDetails?.nameOfHolder,
gender = personDetails?.gender?.name,
documentNumber = personDetails?.documentNumber,
dateOfExpiry = DateUtils.toReadableDate(formatStandardDate(personDetails?.dateOfExpiry)),
dateOfExpiry = DateUtils.toReadableDate(formatStandardDate(personDetails?.dateOfExpiry, threshold = EXPIRY_DATE_THRESHOLD)),
issuingState = personDetails?.issuingState,
nationality = personDetails?.nationality,
otherNames = additionalPersonDetails?.otherNames?.arrayToString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ package org.idpass.smartscanner.lib.nfc.passport
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import org.idpass.smartscanner.lib.R
import org.idpass.smartscanner.lib.databinding.FragmentPassportDetailsBinding
Expand Down Expand Up @@ -88,6 +90,7 @@ class PassportDetailsFragment : androidx.fragment.app.Fragment() {
refreshData(passport)
}

@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("SetTextI18n")
private fun refreshData(passport: Passport?) {
if (passport == null) return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,33 @@
package org.idpass.smartscanner.lib.utils

import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.RequiresApi
import org.idpass.smartscanner.lib.scanner.config.Language
import java.text.DateFormat
import java.text.ParseException
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.util.*

object DateUtils {

private val dateFormat = SimpleDateFormat("yyyy/MM/dd", Locale.ROOT)


/**
* DATE THRESHOLD is for the staring year of date parsing yy -> yyyy
* Example:
* With THRESHOLD = 99, start date will be 99 years ago from present year
* PRESENT_YEAR = 2023
* LOWEST DATE = PRESENT_YEAR - THRESHOLD = 1924
* HIGHEST DATE = 2023
* 240101 -> 01/01/1924
* 230101 -> 01/01/2023
*/
const val BIRTH_DATE_THRESHOLD = 99
const val EXPIRY_DATE_THRESHOLD = 49

fun isValidDate(inDate: String): Boolean {
dateFormat.isLenient = false
try {
Expand All @@ -39,12 +56,34 @@ object DateUtils {
}
fun formatDate(date: Date) : String = dateFormat.format(date)

@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("SimpleDateFormat")
fun formatStandardDate(dateString: String?, fromPattern: String = "yyMMdd", toPattern: String = "MM/dd/yyyy", locale: Locale? = Locale(Language.EN)): String? {
fun formatStandardDate(dateString: String?, fromPattern: String = "yyMMdd", toPattern: String = "MM/dd/yyyy", locale: Locale? = Locale(Language.EN), threshold: Int? = null): String? {
if(fromPattern === "yyMMdd") {
val date = stringToDate2DigitsYear(dateString, threshold) ?: return null
return dateToString(date, SimpleDateFormat(toPattern, locale))
}

val date = stringToDate(dateString, SimpleDateFormat(fromPattern)) ?: return null
return dateToString(date, SimpleDateFormat(toPattern, locale))
}

@RequiresApi(Build.VERSION_CODES.O)
private fun stringToDate2DigitsYear(dateStr: String?, threshold: Int? = null): Date? {
if (dateStr == null || threshold == null) return null
var date: Date? = null
try {
val sdf = SimpleDateFormat("dd/MM/yyyy");
val startYear = LocalDate.now().minusYears(threshold.toLong()).year
sdf.set2DigitYearStart(sdf.parse("01/01/$startYear"))
sdf.applyPattern("yyMMdd")
date = sdf.parse(dateStr)
} catch (e: ParseException) {
e.printStackTrace()
}
return date
}

private fun stringToDate(dateStr: String?, dateFormat: DateFormat): Date? {
if (dateStr == null) return null
var date: Date? = null
Expand Down

0 comments on commit e51d9e5

Please sign in to comment.