Skip to content

Commit

Permalink
Convert date to text representation
Browse files Browse the repository at this point in the history
Converts a given date in brazilian format to its textual
representation.

394
  • Loading branch information
BeneBr committed Sep 20, 2024
1 parent 7bd5b3a commit 420b6b9
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 21 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ emulate bash -c '. .../bin/activate'
Para testar se o ambiente virtual está ativo corretamente, execute o comando e verifique se a resposta é algo parecido com a seguinte:

```sh
$ poetry env inf
$ poetry env info
Virtualenv
Python: 3.x.y
Implementation: CPython
Expand Down
5 changes: 5 additions & 0 deletions brutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
remove_symbols as remove_symbols_cpf,
)

# Date imports
from brutils.date import convert_date_to_text

# Email Import
from brutils.email import is_valid as is_valid_email

Expand Down Expand Up @@ -136,6 +139,8 @@
"generate_cpf",
"is_valid_cpf",
"remove_symbols_cpf",
# Date
"convert_date_to_text",
# Email
"is_valid_email",
# Legal Process
Expand Down
57 changes: 57 additions & 0 deletions brutils/data/enums/months.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from brutils.data.enums.better_enum import BetterEnum


class MonthsEnum(BetterEnum):
JANEIRO = 1
FEVEREIRO = 2
MARCO = 3
ABRIL = 4
MAIO = 5
JUNHO = 6
JULHO = 7
AGOSTO = 8
SETEMBRO = 9
OUTUBRO = 10
NOVEMBRO = 11
DEZEMBRO = 12

@property
def mont_name(self) -> str:
if self == MonthsEnum.JANEIRO:
return "janeiro"
elif self == MonthsEnum.FEVEREIRO:
return "fevereiro"
elif self == MonthsEnum.MARCO:
return "marco"
elif self == MonthsEnum.ABRIL:
return "abril"
elif self == MonthsEnum.MAIO:
return "maio"
elif self == MonthsEnum.JUNHO:
return "junho"
elif self == MonthsEnum.JULHO:
return "julho"
elif self == MonthsEnum.AGOSTO:
return "agosto"
elif self == MonthsEnum.SETEMBRO:
return "setembro"
elif self == MonthsEnum.OUTUBRO:
return "outubro"
elif self == MonthsEnum.NOVEMBRO:
return "novembro"
else:
return "dezembro"

@classmethod
def is_valid_month(cls, month: int) -> bool:
"""
Checks if the given month value is valid.
Args:
month (int): The month to check.
Returns:
True if the month is valid, False otherwise.
"""
return (
True if month in set(month.value for month in MonthsEnum) else False
)
64 changes: 64 additions & 0 deletions brutils/date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import re
from typing import Union

from num2words import num2words

from brutils.data.enums.months import MonthsEnum


def convert_date_to_text(date: str) -> Union[str, None]:
"""
Converts a given date in Brazilian format (dd/mm/yyyy) to its textual representation.
This function takes a date as a string in the format dd/mm/yyyy and converts it
to a string with the date written out in Brazilian Portuguese, including the full
month name and the year.
Args:
date (str): The date to be converted into text. Expected format: dd/mm/yyyy.
Returns:
str or None: A string with the date written out in Brazilian Portuguese,
or None if the date is invalid.
"""
pattern = re.compile(r"\d{2}/\d{2}/\d{4}")
if not re.match(pattern, date):
raise ValueError(
"Date is not a valid date. Please pass a date in the format dd/mm/yyyy."
)

day_str, month_str, year_str = date.split("/")
day = int(day_str)
month = int(month_str)
year = int(year_str)

if 0 <= day > 31:
return None

if not MonthsEnum.is_valid_month(month):
return None

# Leap year.
if MonthsEnum(int(month)) is MonthsEnum.FEVEREIRO:
if (int(year) % 4 == 0 and int(year) % 100 != 0) or (
int(year) % 400 == 0
):
if day > 29:
return None
else:
if day > 28:
return None

day_string = "Primeiro" if day == 1 else num2words(day, lang="pt")
month = MonthsEnum(month)
year_string = num2words(year, lang="pt")

date_string = (
day_string.capitalize()
+ " de "
+ month.mont_name
+ " de "
+ year_string
)
return date_string
64 changes: 44 additions & 20 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ classifiers = [

[tool.poetry.dependencies]
python = "^3.8.1"
num2words = "0.5.13"

[tool.poetry.group.test.dependencies]
coverage = "^7.2.7"
Expand Down
58 changes: 58 additions & 0 deletions tests/test_date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from unittest import TestCase

from num2words import num2words

from brutils.date import convert_date_to_text


class TestNum2Words(TestCase):
def test_num_conversion(self) -> None:
"""
Smoke test of the num2words library.
This test is used to guarantee that our dependency still works.
"""
self.assertEqual(num2words(30, lang="pt-br"), "trinta")
self.assertEqual(num2words(42, lang="pt-br"), "quarenta e dois")
self.assertEqual(
num2words(2024, lang="pt-br"), "dois mil e vinte e quatro"
)
self.assertEqual(num2words(0, lang="pt-br"), "zero")
self.assertEqual(num2words(-1, lang="pt-br"), "menos um")


class TestDate(TestCase):
def test_convert_date_to_text(self):
self.assertEqual(
convert_date_to_text("15/08/2024"),
"Quinze de agosto de dois mil e vinte e quatro",
)
self.assertEqual(
convert_date_to_text("01/01/2000"),
"Primeiro de janeiro de dois mil",
)
self.assertEqual(
convert_date_to_text("31/12/1999"),
"Trinta e um de dezembro de mil novecentos e noventa e nove",
)

#
self.assertIsNone(convert_date_to_text("30/02/2020"), None)
self.assertIsNone(convert_date_to_text("30/00/2020"), None)
self.assertIsNone(convert_date_to_text("30/02/2000"), None)
self.assertIsNone(convert_date_to_text("50/09/2000"), None)
self.assertIsNone(convert_date_to_text("25/15/2000"), None)

# Invalid date pattern.
self.assertRaises(ValueError, convert_date_to_text, "Invalid")
self.assertRaises(ValueError, convert_date_to_text, "25/1/2020")
self.assertRaises(ValueError, convert_date_to_text, "1924/08/20")
self.assertRaises(ValueError, convert_date_to_text, "5/09/2020")

self.assertEqual(
convert_date_to_text("29/02/2020"),
"Vinte e nove de fevereiro de dois mil e vinte",
)
self.assertEqual(
convert_date_to_text("01/01/1900"),
"Primeiro de janeiro de mil e novecentos",
)

0 comments on commit 420b6b9

Please sign in to comment.