Search code examples
flutterdartdate-formattingflutter-intlmrz

Flutter facing issue with passport MRZ 2 digit year code


am new to flutter, in my project am scanning passport MRZ line using google ml kit and parse the data.

Am facing issue when user birthdate is 23-04-2000 , in this case MRZ will be 000423.

and I trying to convert to dd-MM-yyyy format facing issue.

Please help :)

I tried below code by using

String convertMrzDate(String dateStr) {
  String year = dateStr.substring(0, 2);
  String month = dateStr.substring(2, 4);
  String day = dateStr.substring(4, 6);

  int currentYear = DateTime.now().year;
  int currentTwoDigitYear = currentYear % 100;

  int twoDigitYear = int.parse(year);
  int century = (currentYear ~/ 100) * 100;

  int centuryAdjustedYear;
  if (twoDigitYear <= currentTwoDigitYear) {
    centuryAdjustedYear = century + twoDigitYear;
  } else {
    centuryAdjustedYear = century - 100 + twoDigitYear;
  }

  String formattedDate = '$centuryAdjustedYear-$month-$day';
  return formattedDate;
}

it is working for birthdate but expiry date getting wrong data.

My Java Code

 public  static String convertMrzDate(String dateStr) throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd", Locale.ENGLISH);
    Date d1 = sdf.parse(dateStr);
    sdf.applyPattern("yyyy-MM-dd");
    return sdf.format(d1);
}

I tried below dart code using plugin:intl but getting error

Trying to read MM from 000423 at position 6

    String convertMrzDate(String dateStr) {
  final inputFormat = DateFormat('yyMMdd', 'en_US');
  final outputFormat = DateFormat('yyyy-MM-dd');

  final date = inputFormat.parse(dateStr);
  final formattedDate = outputFormat.format(date);

  return formattedDate;
}

Solution

  • You currently do:

    if (twoDigitYear <= currentTwoDigitYear) {
      centuryAdjustedYear = century + twoDigitYear;
    } else {
      centuryAdjustedYear = century - 100 + twoDigitYear;
    }
    

    so any year in the future will be treated as being from the 1900s. That won't work for expiration dates, which usually would be in the near future.

    You instead should use something like the -80/+20 rule that DateFormat from package:intl uses. If you want to re-use DateFormat's existing logic, just reformat your original String to include delimiters, and then you can use DateFormat.parse directly:

    import 'package:intl/intl.dart';
    
    String convertMrzDate(String dateStr) {
      String year = dateStr.substring(0, 2);
      String month = dateStr.substring(2, 4);
      String day = dateStr.substring(4, 6);
    
      var delimited = '$year-$month-$day';
      var dateTime = DateFormat('yy-MM-dd').parse(delimited);
      return DateFormat('dd-MM-yyyy').format(dateTime);
    }
    
    
    void main() {
      print(convertMrzDate('000423')); // Prints: 23-04-2000
      print(convertMrzDate('241031')); // Prints: 31-10-2024
      print(convertMrzDate('991031')); // Prints: 31-10-1999
    }
    

    or if you want to implement your own rule:

    /// Converts a two-digit year to a full year.
    ///
    /// The returned year will be within `lookBehindYears` (exclusive)
    /// before the current year and `100 - lookBehindYears` (inclusive) after
    /// the current year.
    int fromTwoDigitYear(int twoDigitYear, {int lookBehindYears = 80}) {
      assert(twoDigitYear >= 0);
      assert(twoDigitYear < 100);
      assert(lookBehindYears >= 0);
      assert(lookBehindYears < 100);
    
      var thisYear = DateTime.now().year;
      var thisCentury = (thisYear ~/ 100) * 100;
    
      var treatAsEarlier =
          twoDigitYear > (thisYear % 100 + (100 - lookBehindYears));
      return thisCentury + twoDigitYear + (treatAsEarlier ? -100 : 0);
    }
    
    void main() {
      // Printed output from the year 2023.
      print(fromTwoDigitYear(0));  // Prints: 2000
      print(fromTwoDigitYear(99)); // Prints: 1999
      print(fromTwoDigitYear(85)); // Prints: 1985
      print(fromTwoDigitYear(30)); // Prints: 2030
      print(fromTwoDigitYear(40)); // Prints: 2040
      print(fromTwoDigitYear(42)); // Prints: 2042
      print(fromTwoDigitYear(43)); // Prints: 2043
      print(fromTwoDigitYear(44)); // Prints: 1944
    }