Flutter在处理护照MRZ时遇到问题,2位年份代码。

huangapple go评论52阅读模式
英文:

Flutter facing issue with passport MRZ 2 digit year code

问题

I understand your request. Here's the translated code:

我刚接触Flutter,在我的项目中,我使用Google ML Kit扫描护照MRZ行并解析数据

当用户的出生日期是23-04-2000时,MRZ将是000423

我尝试将其转换为dd-MM-yyyy格式时遇到问题

请帮助 :)

我尝试以下代码:

```dart
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;
}

它适用于出生日期,但到期日期获取了错误的数据。

我的Java代码如下:

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);
}

我尝试以下Dart代码,使用了intl插件,但出现错误。

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;
}

希望这可以帮助解决您的问题。


<details>
<summary>英文:</summary>

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(&quot;yyMMdd&quot;, Locale.ENGLISH);
        Date d1 = sdf.parse(dateStr);
        sdf.applyPattern(&quot;yyyy-MM-dd&quot;);
        return sdf.format(d1);
    }

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

&gt; 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;
}


   

</details>


# 答案1
**得分**: 1

你目前正在执行以下操作:

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

因此,将来的任何年份都将被视为来自1900年代。 这对于通常位于不久的将来的到期日期不起作用。

相反,你应该使用类似 DateFormat from package:intl 使用的 -80/+20 规则。 如果要重用 DateFormat 的现有逻辑,只需重新格式化原始 String 以包含分隔符,然后可以直接使用 DateFormat.parse

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);
}

或者,如果要实现自己的规则:

/// 将两位数年份转换为完整年份。
///
/// 返回的年份将位于当前年份的 `lookBehindYears`(不包括在内)
/// 之前和 `100 - lookBehindYears`(包括在内)之后。
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);
}
英文:

You currently do:

> dart
&gt; if (twoDigitYear &lt;= currentTwoDigitYear) {
&gt; centuryAdjustedYear = century + twoDigitYear;
&gt; } else {
&gt; centuryAdjustedYear = century - 100 + twoDigitYear;
&gt; }
&gt;

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 &#39;package:intl/intl.dart&#39;;

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

  var delimited = &#39;$year-$month-$day&#39;;
  var dateTime = DateFormat(&#39;yy-MM-dd&#39;).parse(delimited);
  return DateFormat(&#39;dd-MM-yyyy&#39;).format(dateTime);
}


void main() {
  print(convertMrzDate(&#39;000423&#39;)); // Prints: 23-04-2000
  print(convertMrzDate(&#39;241031&#39;)); // Prints: 31-10-2024
  print(convertMrzDate(&#39;991031&#39;)); // 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 &gt;= 0);
  assert(twoDigitYear &lt; 100);
  assert(lookBehindYears &gt;= 0);
  assert(lookBehindYears &lt; 100);

  var thisYear = DateTime.now().year;
  var thisCentury = (thisYear ~/ 100) * 100;

  var treatAsEarlier =
      twoDigitYear &gt; (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
}

答案2

得分: 0

使用如果大于则添加的方法,这样就可以修复大多数年份错误,检查不依赖于年份的*YY--*部分,所以你不能确定只看这个字符串是不是正确的。

DateTime? mzt_parse_date(String date, String check) {
  final cut_year = 69;  // 和 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)),
    );
  }
}

要得到dd-mm-yyyy,你可以在这一行做和之前一样的操作,但是反过来。

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

或者使用Datetime类型。

String date_to_ddmmyyyy(DateTime date) {
  return '${date.day}-${date.month}-${date.year}';
}
英文:

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(&#39;&lt;&#39;, &#39;0&#39;);
  
  final check_nums = [7, 3, 1, 7, 3, 1];
  final date_chars = exp_date.split(&#39;&#39;);
  assert(date_chars.length == check_nums.length);

  var sum = 0;
  for (var i = 0; i &lt; 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 &lt; 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 = &#39;$centuryAdjustedYear-$month-$day&#39;;

Or use the Datetime type.

String date_to_ddmmyyyy(DateTime date) {
  return &#39;${date.day}-${date.month}-${date.year}&#39;;
}

huangapple
  • 本文由 发表于 2023年5月17日 14:02:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76268973.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定