Skip to content

GetInfo 添加获取年龄#70

Open
mengxw777 wants to merge 2 commits into
guanguans:mainfrom
mengxw777:main
Open

GetInfo 添加获取年龄#70
mengxw777 wants to merge 2 commits into
guanguans:mainfrom
mengxw777:main

Conversation

@mengxw777
Copy link
Copy Markdown

@mengxw777 mengxw777 commented Jan 21, 2026

PR Type

Enhancement


Description

  • Add age calculation functionality to GetInfo method

  • Import time package for birthday-based age computation

  • Add Age field to IdInfo struct for age information

  • Implement getAge helper function with YearDay logic


Diagram Walkthrough

flowchart LR
  A["GetInfo function"] -->|calls| B["getAge helper"]
  B -->|calculates age from| C["birthday time.Time"]
  C -->|returns| D["Age field in IdInfo"]
Loading

File Walkthrough

Relevant files
Enhancement
helper.go
Add getAge helper function for age calculation                     

helper.go

  • Import time package for time-based operations
  • Add new getAge function that calculates age from birthday
  • Function accounts for whether birthday has occurred this year using
    YearDay comparison
+14/-0   
id_validator.go
Add Age field and calculation to IdInfo                                   

id_validator.go

  • Add Age field to IdInfo struct
  • Call getAge function in GetInfo method to calculate age from birthday
  • Include calculated age in returned IdInfo struct
+4/-0     

Summary by CodeRabbit

发布说明

  • 新功能
    • 身份信息系统新增年龄自动计算并在返回的身份信息中显示年龄。
    • 地址库大幅扩展,新增更多省市区县及香港、澳门、台湾的区划条目,提升地址覆盖范围与准确性。

✏️ Tip: You can customize this high-level summary in your review settings.

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Jan 21, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Age edge cases: getAge does not defensively handle edge cases (e.g., zero/future birthdays, timezone
normalization, or Feb-29 behavior across non-leap years), which can yield incorrect or
negative ages.

Referred Code
// getAge 计算年龄
func getAge(birthday time.Time) int {
	now := time.Now()
	age := now.Year() - birthday.Year()

	// 如果今年还没过生日,年龄减1
	if now.YearDay() < birthday.YearDay() {
		age--
	}

	return age

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 21, 2026

Walkthrough

新增一个非导出年龄计算辅助函数并引入 time 包;在 IdInfo 中加入 Age 字段并在 GetInfo 中计算赋值;扩展并补充地址编码及其时间线数据,增加大量行政区映射与时间线条目。

Changes

Cohort / File(s) Summary
年龄计算辅助
helper.go
新增 time 导入与非导出函数 calculateAge(birthday time.Time) int,按当前年/月/日判断并返回年龄。
身份信息与接口
id_validator.go
IdInfo 结构体新增公有字段 Age intGetInfo 改为调用 generateCode(id) 并直接返回其错误;解析生日后调用 calculateAge 并将 Age 包含在返回值中。
地址编码数据
data/address_code.go
大规模扩展返回的地址编码映射,添加多个省市/特别行政区/港澳台条目(新增键值对众多)。注意存在重复键(如 230119/230112 同名)会导致后者覆盖前者。
地址编码时间线
data/address_code_timeline.go
调整河北若干区县的时间区间,新增黑龙江 230119 的时间线条目;将香港、澳门、台湾的时间线由单条扩展为多个区/县条目(多条空起止年记录)。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🐰 风中数岁月,代码轻轻添一行,
我用时光为你算,生日前后分明朗,
地址表铺天地,区县名字连成行,
小兔跳跃庆更新,代码与春同芳。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰准确地反映了主要变更:为GetInfo方法添加年龄获取功能,符合简洁明确的要求。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Jan 21, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Avoid storing volatile derived data

Replace the Age field in the IdInfo struct with an Age() method. This ensures
the age is calculated dynamically from the Birthday field, preventing the value
from becoming stale over time.

Examples:

id_validator.go [28-112]
	Age           int
}

// IsValid 验证身份证号合法性
func IsValid(id string, strict bool) bool {
	code, err := generateCode(id)
	if err != nil {
		return false
	}


 ... (clipped 75 lines)

Solution Walkthrough:

Before:

// id_validator.go
type IdInfo struct {
    // ...
    Birthday      time.Time
    Age           int
}

func GetInfo(id string, strict bool) (IdInfo, error) {
    // ...
    birthday, _ := time.ParseInLocation(...)
    age := getAge(birthday) // Calculated once

    return IdInfo{
        // ...
        Birthday:      birthday,
        Age:           age, // Stored value
    }, nil
}

After:

// id_validator.go
type IdInfo struct {
    // ...
    Birthday      time.Time
    // Age field is removed
}

// New method on IdInfo
func (info *IdInfo) Age() int {
    return getAge(info.Birthday) // Calculate on-demand
}

func GetInfo(id string, strict bool) (IdInfo, error) {
    // ...
    birthday, _ := time.ParseInLocation(...)
    // age calculation is removed from here
    return IdInfo{
        // ...
        Birthday: birthday,
    }, nil
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a significant design flaw where storing the calculated Age can lead to stale data, and proposes a robust alternative by calculating it on-demand via a method.

High
Possible issue
Fix bug in age calculation
Suggestion Impact:Updated the age calculation logic to use month/day comparisons instead of YearDay(), matching the suggested leap-year-safe approach (function was also renamed to calculateAge).

code diff:

-// getAge 计算年龄
-func getAge(birthday time.Time) int {
+// calculateAge 计算年龄
+func calculateAge(birthday time.Time) int {
 	now := time.Now()
 	age := now.Year() - birthday.Year()
-
-	// 如果今年还没过生日,年龄减1
-	if now.YearDay() < birthday.YearDay() {
+	// 检查生日是否已经过了今年
+	if now.Month() < birthday.Month() || (now.Month() == birthday.Month() && now.Day() < birthday.Day()) {
 		age--
 	}
-
 	return age

Fix a bug in the getAge function by replacing the flawed YearDay() comparison
with a more robust check of month and day to correctly handle leap years.

helper.go [142-153]

 // getAge 计算年龄
 func getAge(birthday time.Time) int {
 	now := time.Now()
 	age := now.Year() - birthday.Year()
 
 	// 如果今年还没过生日,年龄减1
-	if now.YearDay() < birthday.YearDay() {
+	if now.Month() < birthday.Month() || (now.Month() == birthday.Month() && now.Day() < birthday.Day()) {
 		age--
 	}
 
 	return age
 }

[Suggestion processed]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a bug in the age calculation logic related to leap years and provides a robust fix, which is critical for the correctness of this new function.

High
  • Update

@mengxw777 mengxw777 closed this Jan 28, 2026
@guanguans guanguans reopened this Apr 6, 2026
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add age calculation and supplement address code data

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add age calculation feature to ID card information retrieval
• Supplement historical address code data for multiple provinces
• Expand address code coverage for Hong Kong, Macau, and Taiwan regions
• Fix address code timeline data inconsistencies and formatting
Diagram
flowchart LR
  A["ID Validator"] -->|"Parse ID"| B["Generate Code"]
  B -->|"Extract Birthday"| C["Calculate Age"]
  C -->|"Return Info"| D["IdInfo with Age"]
  A -->|"Address Code"| E["Address Database"]
  E -->|"Supplement Data"| F["Enhanced Coverage"]
Loading

Grey Divider

File Changes

1. data/address_code.go Data/configuration +102/-0

Supplement comprehensive address code database

• Added missing historical address codes for Beijing, Tianjin, and Hebei provinces
• Expanded address code entries for Shanghai, Jiangsu, Zhejiang, and other provinces
• Added complete address code mappings for Hong Kong, Macau, and Taiwan regions
• Filled gaps in district-level address codes across mainland China

data/address_code.go


2. data/address_code_timeline.go Data/configuration +305/-19

Fix and expand address code timeline data

• Corrected historical timeline data for Hebei province address codes
• Fixed start and end year values for county-level administrative divisions
• Expanded Hong Kong districts timeline with 18 new district entries
• Added Macau and Taiwan region timeline data with empty year placeholders
• Reformatted Hong Kong function return statement for better code structure

data/address_code_timeline.go


3. helper.go ✨ Enhancement +12/-0

Add age calculation helper function

• Added time package import for date/time operations
• Implemented new calculateAge() function to compute age from birthday
• Function accounts for whether birthday has occurred in current year

helper.go


View more (1)
4. id_validator.go ✨ Enhancement +7/-5

Add age field to ID information structure

• Added Age field to IdInfo struct for age information
• Modified GetInfo() function to calculate and return age
• Improved error handling by checking generateCode() error explicitly
• Removed redundant validation check in GetInfo() function

id_validator.go


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 6, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX Issues (0)

Grey Divider


Action required

1. GetInfo skips validation 🐞 Bug ≡ Correctness
Description
GetInfo no longer validates order/birthday/address/checkbit and will return nil error for invalid
IDs (including strict=true), producing incorrect Address/Birthday/Sex/Age results. This regresses
existing behavior and breaks the current unit test expectation that strict GetInfo returns an error
for IDs invalid in strict mode.
Code

id_validator.go[R63-67]

func GetInfo(id string, strict bool) (IdInfo, error) {
-	// 验证有效性
-	if !IsValid(id, strict) {
-		return IdInfo{}, errors.New("invalid ID card number")
+	code, err := generateCode(id)
+	if err != nil {
+		return IdInfo{}, err
	}
-
-	code, _ := generateCode(id)
Evidence
GetInfo now only checks generateCode length/regex parsing errors, while IsValid contains the actual
ID validation rules (birthday/address/checkbit). generateLongCode’s regex matches any 18-char string
(not digits-only), so many invalid IDs will still parse and GetInfo will proceed. The repository’s
TestGetInfo explicitly expects GetInfo(..., true) to fail for an ID that is invalid in strict mode,
which will no longer happen.

id_validator.go[62-98]
id_validator.go[31-50]
checker.go[53-70]
id_validator_test.go[63-77]
id_validator_basic.go[42-47]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`GetInfo` currently returns parsed info even when the ID is invalid (including `strict=true`) because it no longer performs the same validation as `IsValid`.

### Issue Context
- `generateCode` only checks length and does permissive regex extraction; it does **not** validate birthday/address/checkbit.
- `IsValid` already encodes the library’s validation rules.

### Fix Focus Areas
- id_validator.go[62-67]
- id_validator.go[31-50]

### Suggested fix
Option A (simplest):
- Reintroduce `if !IsValid(id, strict) { return IdInfo{}, errors.New("invalid ID card number") }` at the top of `GetInfo`.

Option B (avoid double parsing):
- Keep the single `generateCode` call, but immediately apply the same checks as `IsValid` (order/birthday/address and for 18-digit IDs checkbit) and return the same error when validation fails.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Age timezone mismatch 🐞 Bug ☼ Reliability
Description
calculateAge uses time.Now() in the process-local timezone while Birthday is parsed in
Asia/Shanghai; in non-CST deployments this can compute an off-by-one Age around date boundaries. Age
should be calculated using the same location as the parsed birthday (or an explicit consistent
timezone).
Code

helper.go[R142-149]

+// calculateAge 计算年龄
+func calculateAge(birthday time.Time) int {
+	now := time.Now()
+	age := now.Year() - birthday.Year()
+	// 检查生日是否已经过了今年
+	if now.Month() < birthday.Month() || (now.Month() == birthday.Month() && now.Day() < birthday.Day()) {
+		age--
+	}
Evidence
GetInfo parses birthday using the Asia/Shanghai (CST) location, but calculateAge compares month/day
against time.Now() without converting to the same location. If the server runs in UTC (or any
non-CST timezone), the ‘current date’ used for comparison can differ from CST, making age incorrect
near midnight.

id_validator.go[80-87]
helper.go[142-150]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`calculateAge` uses `time.Now()` without aligning timezone to the birthday parsing timezone, which can yield off-by-one ages.

### Issue Context
`GetInfo` parses birthday in `Asia/Shanghai` / fixed CST.

### Fix Focus Areas
- helper.go[142-150]
- id_validator.go[80-87]

### Suggested fix
Update `calculateAge` to compute `now` in the same location as `birthday`, e.g.:
```go
now := time.Now().In(birthday.Location())
```
(Alternatively, pass the CST location into `calculateAge` or load `Asia/Shanghai` inside it for consistency.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Nondeterministic address generation 🐞 Bug ≡ Correctness
Description
New AddressCode entries add duplicate address names (e.g., "阿城区" and "云岩区" for multiple codes), and
generatorAddressCode returns the first match from a Go map iteration, which is randomized. This
makes FakeRequireId/address-based code generation produce inconsistent results between runs for the
same address string.
Code

data/address_code.go[689]

+		230119: "阿城区",
Evidence
AddressCode now contains multiple keys with identical address strings (e.g., 230112 and 230119 both
map to "阿城区"; 520101 and 520103 both map to "云岩区"). generatorAddressCode linearly scans
data.AddressCode() and breaks on the first match, but Go map iteration order is not stable, so the
selected code for a duplicated address string can change across runs. FakeRequireId calls
generatorAddressCode when an address string is provided, so this nondeterminism is externally
observable.

data/address_code.go[686-690]
data/address_code.go[2524-2529]
data/address_code.go[2770-2774]
generator.go[45-52]
id_validator.go[124-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`generatorAddressCode` picks an arbitrary code when multiple codes share the same address name because it iterates over a map and stops at the first match.

### Issue Context
Recent data additions introduced more duplicate address-name values, increasing the likelihood of nondeterministic outputs.

### Fix Focus Areas
- generator.go[45-52]
- data/address_code.go[686-690]
- data/address_code.go[2524-2529]

### Suggested fix
Make selection deterministic when multiple codes map to the same address string, e.g.:
- Collect all matching codes, sort ascending, pick the smallest (or prefer non-abandoned / most recent by timeline if you want smarter behavior).
- Alternatively, build a reverse index (address -> sorted codes) at init time and use it here.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread id_validator.go
Comment on lines 63 to 67
func GetInfo(id string, strict bool) (IdInfo, error) {
// 验证有效性
if !IsValid(id, strict) {
return IdInfo{}, errors.New("invalid ID card number")
code, err := generateCode(id)
if err != nil {
return IdInfo{}, err
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Getinfo skips validation 🐞 Bug ≡ Correctness

GetInfo no longer validates order/birthday/address/checkbit and will return nil error for invalid
IDs (including strict=true), producing incorrect Address/Birthday/Sex/Age results. This regresses
existing behavior and breaks the current unit test expectation that strict GetInfo returns an error
for IDs invalid in strict mode.
Agent Prompt
### Issue description
`GetInfo` currently returns parsed info even when the ID is invalid (including `strict=true`) because it no longer performs the same validation as `IsValid`.

### Issue Context
- `generateCode` only checks length and does permissive regex extraction; it does **not** validate birthday/address/checkbit.
- `IsValid` already encodes the library’s validation rules.

### Fix Focus Areas
- id_validator.go[62-67]
- id_validator.go[31-50]

### Suggested fix
Option A (simplest):
- Reintroduce `if !IsValid(id, strict) { return IdInfo{}, errors.New("invalid ID card number") }` at the top of `GetInfo`.

Option B (avoid double parsing):
- Keep the single `generateCode` call, but immediately apply the same checks as `IsValid` (order/birthday/address and for 18-digit IDs checkbit) and return the same error when validation fails.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
id_validator.go (1)

85-85: ⚠️ Potential issue | 🟡 Minor

生日解析错误被忽略。

time.ParseInLocation 的错误被 _ 忽略。若解析失败,birthday 将为零值时间,calculateAge 会返回约 2000+ 的异常年龄。

考虑到上述验证逻辑移除问题,建议处理此错误:

-	birthday, _ := time.ParseInLocation("20060102", code["birthdayCode"], cst)
+	birthday, err := time.ParseInLocation("20060102", code["birthdayCode"], cst)
+	if err != nil {
+		return IdInfo{}, errors.New("invalid birthday code")
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@id_validator.go` at line 85, The call to time.ParseInLocation ignores the
error, so a failed parse leaves birthday as the zero time and calculateAge
returns an absurd value; update the parsing in the function that calls
time.ParseInLocation("20060102", code["birthdayCode"], cst) to capture the
returned error, validate it, and handle it (e.g., return an explicit validation
error or false result) instead of discarding it—ensure you reference the parsed
variable birthday and the downstream calculateAge call when adding the error
check so invalid birthdayCode values are rejected early.
🧹 Nitpick comments (1)
data/address_code.go (1)

3282-3324: 港澳台区县码这批新增数据当前不会被读取。

helper.go Line 17-29 对首位为 8 的地址码在解析完省级后就直接返回,checker.go Line 74-91 也只要求省级非空。所以 810101-810118820101-820103830101-830120 这批新增项不会进入 GetInfo/校验链路;现在只是和 AddressCodeTimeline 并行维护的一份不可达数据。若目标是支持这些子区域,需要同步放开早返回逻辑;否则建议不要继续在这里扩充这类条目。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@data/address_code.go` around lines 3282 - 3324, The new HK/MO/TW sub-region
codes (codes starting with '8') are never used because helper.go currently
returns early after parsing province-level for codes whose first digit is '8'
and checker.go only requires province-level non-empty; to fix, either stop
adding these subregions or enable them by removing the early-return in the
helper function that handles address parsing (the logic that bails out after
province for leading '8') so GetInfo will continue parsing city/district levels,
and update the validation in checker.go (the checker that only asserts province
non-empty) to validate/allow deeper fields for codes starting with '8' so the
AddressCodeTimeline entries become reachable. Ensure tests for GetInfo and the
checker cover codes like 810101, 820101, and 830101.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@data/address_code.go`:
- Line 605: 这批以 xxxx01 结尾的历史码在 address_code.go 中被当成具体区名(例如
220101、420101、520101、620101 等),但 helper.go 注释(line 44-58)说明自 1984 年起 xxxx01
应为“市辖区”汇总码,具体区应使用 xxxx11 或其它历史编号;请审查 address_code.go 中所有匹配正则 /[0-9]{6}01/
的条目(包含评论提到的 220101、420101、520101、620101 及其同类行),根据 helper.go 的时间线把这些条目改回汇总名“市辖区”
或(若确认存在历史具体区码)把具体区名移动到对应的 xxxx11/正确历史码,并保持时间线回退逻辑一致;在更改时确保与 helper.go
的规则和注释一致,更新或删除重复/错位的具体区字符串以避免代码在有/无时间线时返回不一致地址。

In `@id_validator.go`:
- Around line 97-98: The age calculation uses time.Now() inside calculateAge
causing timezone drift; change calculateAge to accept a now time parameter
(e.g., calculateAge(birthday time.Time, now time.Time)) and update its
implementation in helper.go to compute age using the provided now, then update
the caller (where age := calculateAge(birthday)) to pass a now value that is in
Asia/Shanghai (use time.LoadLocation("Asia/Shanghai") and now.In(cst) when
creating the now argument) so both birthday and now are in the same timezone and
tests remain deterministic.
- Around line 64-67: GetInfo currently only calls generateCode (which only
checks length) so other important validations from IsValid are skipped; restore
the full validation flow by invoking IsValid (or performing the same checks)
inside GetInfo before calling generateCode and return an error when any check
fails; specifically ensure checkOrderCode, checkBirthdayCode, checkAddressCode
and generatorCheckBit are executed (or delegated to IsValid) and that GetInfo
returns an error instead of an IdInfo when any of those validations fail.

---

Outside diff comments:
In `@id_validator.go`:
- Line 85: The call to time.ParseInLocation ignores the error, so a failed parse
leaves birthday as the zero time and calculateAge returns an absurd value;
update the parsing in the function that calls time.ParseInLocation("20060102",
code["birthdayCode"], cst) to capture the returned error, validate it, and
handle it (e.g., return an explicit validation error or false result) instead of
discarding it—ensure you reference the parsed variable birthday and the
downstream calculateAge call when adding the error check so invalid birthdayCode
values are rejected early.

---

Nitpick comments:
In `@data/address_code.go`:
- Around line 3282-3324: The new HK/MO/TW sub-region codes (codes starting with
'8') are never used because helper.go currently returns early after parsing
province-level for codes whose first digit is '8' and checker.go only requires
province-level non-empty; to fix, either stop adding these subregions or enable
them by removing the early-return in the helper function that handles address
parsing (the logic that bails out after province for leading '8') so GetInfo
will continue parsing city/district levels, and update the validation in
checker.go (the checker that only asserts province non-empty) to validate/allow
deeper fields for codes starting with '8' so the AddressCodeTimeline entries
become reachable. Ensure tests for GetInfo and the checker cover codes like
810101, 820101, and 830101.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9b75b6d2-394e-4176-baa4-b7d503f4252e

📥 Commits

Reviewing files that changed from the base of the PR and between 0560ce7 and 4da23f6.

📒 Files selected for processing (4)
  • data/address_code.go
  • data/address_code_timeline.go
  • helper.go
  • id_validator.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • helper.go

Comment thread data/address_code.go
211481: "兴城市",
220000: "吉林省",
220100: "长春市",
220101: "郊区",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

这批 xxxx01 历史码看起来整体错位了。

helper.go Line 44-58 已明确说明:1984 年起地级市的 xxxx01 是“市辖区”汇总码,xxxx11 才开始给具体区/郊区编号。这里却把多处 ...101 录成了具体区名(例如 220101: "郊区"420101: "汉桥区"520101: "云岩区"620101: "红古区")。这样时间线命中时会返回错误地址,而时间线缺失时又会回退成“市辖区”,同一代码会前后不一致。建议先整体复核同类 ...01 条目,确认是否应改为汇总码或 ...11/其他真实历史码。

Also applies to: 1177-1177, 1718-1718, 2526-2526, 2625-2625, 2772-2772, 2974-2974, 3076-3076

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@data/address_code.go` at line 605, 这批以 xxxx01 结尾的历史码在 address_code.go
中被当成具体区名(例如 220101、420101、520101、620101 等),但 helper.go 注释(line 44-58)说明自 1984 年起
xxxx01 应为“市辖区”汇总码,具体区应使用 xxxx11 或其它历史编号;请审查 address_code.go 中所有匹配正则 /[0-9]{6}01/
的条目(包含评论提到的 220101、420101、520101、620101 及其同类行),根据 helper.go 的时间线把这些条目改回汇总名“市辖区”
或(若确认存在历史具体区码)把具体区名移动到对应的 xxxx11/正确历史码,并保持时间线回退逻辑一致;在更改时确保与 helper.go
的规则和注释一致,更新或删除重复/错位的具体区字符串以避免代码在有/无时间线时返回不一致地址。

Comment thread id_validator.go
Comment on lines +64 to 67
code, err := generateCode(id)
if err != nil {
return IdInfo{}, err
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

验证逻辑不完整,可能接受无效身份证号。

移除 IsValid 预检查后,GetInfo 仅调用 generateCode,而 generateCode 只做长度校验。原本 IsValid 中的以下校验被跳过:

  • checkOrderCode (顺序码校验)
  • checkBirthdayCode (出生日期校验)
  • checkAddressCode (地址码校验)
  • generatorCheckBit (18位校验码验证)

这将导致无效身份证号返回包含错误数据的 IdInfo,而非返回错误。

🐛 建议修复:保留完整验证逻辑
 func GetInfo(id string, strict bool) (IdInfo, error) {
+	if !IsValid(id, strict) {
+		return IdInfo{}, errors.New("invalid ID card number")
+	}
 	code, err := generateCode(id)
 	if err != nil {
 		return IdInfo{}, err
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
code, err := generateCode(id)
if err != nil {
return IdInfo{}, err
}
func GetInfo(id string, strict bool) (IdInfo, error) {
if !IsValid(id, strict) {
return IdInfo{}, errors.New("invalid ID card number")
}
code, err := generateCode(id)
if err != nil {
return IdInfo{}, err
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@id_validator.go` around lines 64 - 67, GetInfo currently only calls
generateCode (which only checks length) so other important validations from
IsValid are skipped; restore the full validation flow by invoking IsValid (or
performing the same checks) inside GetInfo before calling generateCode and
return an error when any check fails; specifically ensure checkOrderCode,
checkBirthdayCode, checkAddressCode and generatorCheckBit are executed (or
delegated to IsValid) and that GetInfo returns an error instead of an IdInfo
when any of those validations fail.

Comment thread id_validator.go
Comment on lines +97 to +98
age := calculateAge(birthday)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

时区不一致可能导致年龄计算错误。

birthday 使用 Asia/Shanghai 时区解析 (line 81-85),但 calculateAge 内部使用 time.Now() 获取的是系统本地时间。若服务器部署在其他时区,在跨日边界时刻可能导致年龄计算偏差一岁。

建议在 calculateAge 中也使用统一的时区,或将 now 转换为同一时区后再比较。

🔧 建议修复方案

方案一:在 helper.gocalculateAge 中统一使用 Asia/Shanghai 时区:

func calculateAge(birthday time.Time) int {
	cst, _ := time.LoadLocation("Asia/Shanghai")
	now := time.Now().In(cst)
	// ...
}

方案二:传递 now 参数使其可测试且时区一致:

func calculateAge(birthday time.Time, now time.Time) int {
	age := now.Year() - birthday.Year()
	// ...
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@id_validator.go` around lines 97 - 98, The age calculation uses time.Now()
inside calculateAge causing timezone drift; change calculateAge to accept a now
time parameter (e.g., calculateAge(birthday time.Time, now time.Time)) and
update its implementation in helper.go to compute age using the provided now,
then update the caller (where age := calculateAge(birthday)) to pass a now value
that is in Asia/Shanghai (use time.LoadLocation("Asia/Shanghai") and now.In(cst)
when creating the now argument) so both birthday and now are in the same
timezone and tests remain deterministic.

@guanguans
Copy link
Copy Markdown
Owner

@mengxw777 抱歉刚看到,不过看起来测试没有通过

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants