Last active
March 5, 2023 08:14
-
-
Save ollipal/d27c33e011e45a6773870fea29279d91 to your computer and use it in GitHub Desktop.
Finnish personal identity code (henkilötunnus/hetu) generator in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
MIT License | |
Copyright (c) 2023 Olli Paloviita | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
""" | |
import datetime | |
from calendar import monthrange | |
from typing import Iterator | |
def hetus( | |
future_hetus: bool = False, | |
temporary_hetus: bool = False, | |
rare_hetus: bool = True, | |
) -> Iterator[str]: | |
"""Finnish personal identity code (henkilötunnus/hetu) generator | |
Yields Finnish personal identity codes one by one, starting from the most common | |
century symbols (-A+) and then the new century symbols introduced in 2023 | |
(BCDEFYXVWU). Finnish personal identity codes are functionally very similar to | |
social security numbers. More info: https://fi.wikipedia.org/wiki/Henkil%C3%B6tunnus | |
Args: | |
future_hetus: Include future hetus that no one can have yet | |
temporary_hetus: Include temporary hetus with numbers 900-999 | |
rare_hetus: Include hetus with rare century symbols (BCDEFYXVWU) | |
Returns: | |
Personal identity code string iterator | |
""" | |
years_since_2000 = datetime.date.today().year - 2000 | |
def century_symbol_to_number(century_symbol): | |
if century_symbol in "+": | |
return 1800 | |
elif century_symbol in "-YXWVU": | |
return 1900 | |
elif century_symbol in "ABCDEF": | |
return 2000 | |
def years_in_century(century_symbol): | |
return ( | |
years_since_2000 + 1 | |
if not future_hetus and century_symbol_to_number(century_symbol) == 2000 | |
else 100 | |
) | |
def days_in_month(century_symbol, year_short, month): | |
year = century_symbol_to_number(century_symbol) + year_short | |
return monthrange(year, month)[1] | |
for century_symbol in "-A+BCDEFYXVWU" if rare_hetus else "-A+": | |
for year_short in range(0, years_in_century(century_symbol)): | |
for month in range(1, 12 + 1): | |
for day in range(1, days_in_month(century_symbol, year_short, month) + 1): | |
date = f"{day:02}{month:02}{year_short:02}" | |
for num in range(2, 1000 if temporary_hetus else 900): | |
check = "0123456789ABCDEFHJKLMNPRSTUVWXY"[int(f"{date}{num:03}") % 31] | |
yield f"{date}{century_symbol}{num:03}{check}" | |
if __name__ == "__main__": | |
# print 276000000+ hetus | |
for hetu in hetus(): | |
print(hetu) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment