A Go library for validating and parsing Serbian unique master citizen numbers (JMBG - Jedinstveni Matični Broj Građana).
- ✅ Validate JMBG numbers with comprehensive checks
- ✅ Extract birth date, region, and gender information
- ✅ Support for all Serbian and ex-Yugoslav regions
- ✅ Calculate age from JMBG
- ✅ Check adult status (18+ years)
- ✅ Zero external dependencies
- ✅ Fully tested with Go testing framework
go get github.com/jmbg-labs/goimport jmbg "github.com/jmbg-labs/go"
// Quick validation
if jmbg.Valid("0101000710009") {
fmt.Println("Valid JMBG")
}
// Parse and validate
j, err := jmbg.Parse("0101000710009")
if err != nil {
fmt.Println("Invalid:", err)
return
}
fmt.Println("Valid:", j.Format())j, err := jmbg.Parse("0101000710009")
if err != nil {
log.Fatal(err)
}
// Birth date
date := j.GetDate() // time.Time
fmt.Println(date.Format("2006-01-02")) // 2000-01-01
// Age
fmt.Println(j.GetAge()) // e.g., 26
// Gender
if j.IsMale() {
fmt.Println("Male")
}
if j.IsFemale() {
fmt.Println("Female")
}
fmt.Println(j.Gender()) // "Male" or "Female"
// Adult check
fmt.Println(j.IsAdult()) // true/false
// Individual fields
fmt.Println(j.Day) // 1
fmt.Println(j.Month) // 1
fmt.Println(j.Year) // 2000
fmt.Println(j.Region) // 71
fmt.Println(j.RegionText) // "Belgrade"
fmt.Println(j.Country) // "Serbia"
fmt.Println(j.Unique) // 0
fmt.Println(j.Checksum) // 9j, _ := jmbg.Parse("1505995800002")
fmt.Println(j.Original) // "1505995800002"
fmt.Println(j.DayOriginal) // "15"
fmt.Println(j.MonthOriginal) // "05"
fmt.Println(j.YearOriginal) // "995"
fmt.Println(j.RegionOriginal) // "80"
fmt.Println(j.UniqueOriginal) // "000"
// String conversion
fmt.Println(j.Format()) // "1505995800002"
fmt.Println(j.String()) // "1505995800002"
fmt.Printf("%s\n", j) // "1505995800002"JMBG consists of 13 digits: DDMMYYYRRBBBC
| Part | Length | Description |
|---|---|---|
| DD | 2 | Day of birth (01–31) |
| MM | 2 | Month of birth (01–12) |
| YYY | 3 | Year of birth (last 3 digits) |
| RR | 2 | Region code |
| BBB | 3 | Unique number (000–499 male, 500–999 female) |
| C | 1 | Checksum digit |
- YYY < 800 →
2000 + YYY(e.g., 000 → 2000) - YYY ≥ 800 →
1000 + YYY(e.g., 978 → 1978)
The library supports all Serbian and ex-Yugoslav regions including (beware: ex-Yugoslav regions codes may have changed since the breakup):
- Serbia (71-79): Belgrade, Kragujevac, Niš, etc.
- Serbia/Vojvodina (80-89): Novi Sad, Subotica, Pančevo, etc.
- Serbia/Kosovo (91-96): Priština, Peć, Prizren, etc.
- Bosnia and Herzegovina (10-19)
- Montenegro (21-29)
- Croatia (30-39)
- Macedonia (41-49)
- Slovenia (50)
The library performs comprehensive validation:
- Length check — Must be exactly 13 digits
- Format check — Must contain only numeric characters
- Date validation — Birth date must be valid (including leap year support)
- Region validation — Region code must exist in the registry
- Checksum validation — Modulo 11 algorithm verification
j, err := jmbg.Parse("1234567890123")
if err != nil {
fmt.Println(err)
// Possible messages:
// - "JMBG string must have exactly 13 digits, got N"
// - "JMBG must contain only numeric characters"
// - "Date 'DD/MM/YYYY' is not valid"
// - "Region 'N' is not valid for JMBG"
// - "Checksum is not valid"
}# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run tests with coverage
go test -cover ./...- Go ^1.21
- No external dependencies (for production use)
Contributions are welcome! Please ensure:
- All tests pass (
go test ./...) - Code follows Go conventions (
go fmt,go vet) - Add tests for new features
- Update documentation as needed
This project is licensed under the MIT License - see the LICENSE file for details.
Developed by JMBG Labs
package main
import (
"fmt"
jmbg "github.com/jmbg-labs/go"
)
func main() {
jmbgs := []string{"0710003730015", "1705978730032", "invalid"}
for _, jmbgString := range jmbgs {
if jmbg.Valid(jmbgString) {
j, _ := jmbg.Parse(jmbgString)
fmt.Printf(
"%s - Born: %s, Region: %s, Gender: %s\n",
j.Format(),
j.GetDate().Format("2006-01-02"),
j.RegionText,
j.Gender(),
)
} else {
fmt.Printf("%s - Invalid\n", jmbgString)
}
}
}j, err := jmbg.Parse("0710003730015")
if err != nil {
log.Fatal(err)
}
age := j.GetAge()
fmt.Printf("Age: %d\n", age)
if j.IsAdult() {
fmt.Println("Adult (18+)")
} else {
fmt.Println("Minor")
}