Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle date parsing for 2 digits year #140

Merged
merged 1 commit into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
nicholemnl marked this conversation as resolved.
Show resolved Hide resolved
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