0

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;
}
abhi
  • 54
  • 8
  • "but expiry date getting wrong data." The logic you have is that any years in the future will be treated as being from the previous century, so what do you expect? If you want a better system, consider something like the -80/+20 rule used by [`package:intl`'s `DateFormat`](https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html). (Or just reformat `'000423'` as `'00-04-23'` and use `DateFormat.parse` directly.) – jamesdlin May 17 '23 at 06:31
  • hi @jamesdlin, actually i want to parse date from yyMMdd to yyyy-MM-dd. Could you please tell me how to do with package:intl's DateFormat – abhi May 17 '23 at 06:55
  • I want to parse from '000423' to '2000-04-23' as birthdate & '320428' as '2023-04-28'. – abhi May 17 '23 at 06:58
  • Not what you asked, I strongly recommend that in Java you don’t use `SimpleDatFormat` and `Date`. Those classes were troublesome and are long outdated. Use `LocalDate` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/index.html). – Ole V.V. May 17 '23 at 07:13
  • Hi @OleV.V. Java code working fine for me, my concern is dart. How I can accomplish it on dart. Am new to flutter. – abhi May 17 '23 at 07:15

2 Answers2

1

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
}
jamesdlin
  • 81,374
  • 13
  • 159
  • 204
0

Use the add x if greater than, that should fix most of the year errors, the check does not rely on the YY-- part of the year so you can't know for sure only locking at that string.

DateTime? mzt_parse_date(String date, String check) {
  final cut_year = 69;  // Same as MySQL
  final exp_date = date.replaceAll('<', '0');
  
  final check_nums = [7, 3, 1, 7, 3, 1];
  final date_chars = exp_date.split('');
  assert(date_chars.length == check_nums.length);

  var sum = 0;
  for (var i = 0; i < date_chars.length; i++) {
    sum += int.parse(date_chars[i]) * check_nums[i];
  }

  if (sum % 10 == int.parse(check)) {
    final year = int.parse(exp_date.substring(0, 2));
    return DateTime(
      year + ((year < cut_year) ? 2000 : 1900),
      int.parse(exp_date.substring(2, 4)),
      int.parse(exp_date.substring(4, 6)),
    );
  }
}

To get a dd-mm-yyyy for you can do the same thing as you did in this line, but backwords.

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

Or use the Datetime type.

String date_to_ddmmyyyy(DateTime date) {
  return '${date.day}-${date.month}-${date.year}';
}
SrPanda
  • 854
  • 1
  • 5
  • 9