Skip to content

Releases: EtorixDev/timelength

v3.0.3

18 Feb 19:17

Choose a tag to compare

  • Fixed several edge cases.
    • ago() / hence() now evaluate “now” per call when base is not provided.
    • Conversion rounding now respects max_precision=0 (instead of treating it like no rounding).
    • Power with modulo now handles zero modulo correctly (ValueError) instead of silently skipping modulo logic.
    • Datetime bound checks now handle naive datetimes consistently by treating them as UTC.
  • Various documentation and repr updates to TimeLength and Guess.
  • Migrated from Poetry to uv.
  • Added Python 3.14 support.

v3.0.2

20 May 02:16

Choose a tag to compare

  • Modify Guess and TimeLength classes so handling of Guess().locales occurs only inside of the Guess class.
  • Modify Guess to make Guess().flags and Guess().settings properties to emphasize that modifying those configurations will not propagate to the internal Locales and to allow for per-locale configuration without being overwritten by the Guess's configuration. They may still be passed as arguments during initialization.
    • To update the flags and settings in Guess().locales post-initialization, iterate over the list and update as necessary.
  • Modify TimeLength so that the Locale chosen during guessing is a deepcopy to prevent accidental modifications.

v3.0.1

10 May 05:50

Choose a tag to compare

  • Minor repr updates to various classes.
    • Fixed a bug where the int value of FailureFlags would show up in ParsedTimeLength's repr instead of the flag names.
  • Minor updates to some of TimeLength's dunder methods.

See aa825a1 and eb4d138 for specifics.

v3.0.0

18 Feb 22:43

Choose a tag to compare

Breaking

  • Python 3.8 is no longer supported.
  • TimeLength().strict is deprecated. Its functionality has been replaced with timelength.FailureFlags and timelength.ParserSettings. Find a full list of options for each in the README.
    • The default for FailureFlags is FailureFlags.NONE which means as long as a single value is parsed, it will be considered a success.
    • The spiritual successor to strict = True is FailureFlags.ALL, which means if any failure flag is met, the parsing will be considered a failure.
  • decimal_separators and thousand_separators in the config were renamed to decimal_delimiters and thousand_delimiters.
    • This will only affect you if you utilized a CustomLocale.
  • CustomLocale was removed in favor of just using Locale.
  • BufferType and buffer_type() renamed to StringType and string_type() respectively.
  • TimeLength().result.invalid and TimeLength().result.valid are now tuples of tuples instead of lists of tuples.
    • The invalid tuple is of type tuple[tuple[float | str, FailureFlags], ...].
    • The valid tuple is of type tuple[tuple[float, Scale], ...].

Features

  • timelength.FailureFlags is an IntFlag enum which holds all the currently possible reasons for a parse to fail. It is not guaranteed that every flag will be used by every parser, but every flag from all parsers will be present. See the README for a full list.
    • Set specific failure flags by passing them to your locale.
    • Example: locale = English(flags=(FailureFlags.LONELY_VALUE | FailureFlags.UNKNOWN_TERM)).
    • In this scenario, parsing will only fail if LONELY_VALUE or UNKNOWN_TERM appear in the result.invalid tuple, or if no valid results were parsed.
  • Modify parsing behavior by passing a timelength.ParserSettings() to locale.settings. It is not guaranteed that every setting will be used by every parser, but every setting from all parsers will be present.
    • Example: locale = English(settings=ParserSettings(allow_duplicate_scales=False))
    • assume_seconds (Literal["LAST", "SINGLE", "NEVER"]): Defaults to SINGLE. How to handle no scale being provided. If seconds are disabled, the first loaded scale will take its place.
      • LAST: Assume seconds only for the last value if no scale is provided for it.
      • SINGLE: Only assume seconds when a single number is provided.
      • NEVER: Never assume seconds when no scale is provided.
    • limit_allowed_terms (bool): Defaults to True. Prevent terms from the allowed_terms list in the config from being used in the middle of a segment/sentence, thus interrupting a value/scale pair. The affected segment will become abandoned and added to the invalid tuple. The terms may still be used at the beginning or end of a segment/sentence. If False, The terms will be ignored (within other limitations) and not affect parsing.
    • allow_duplicate_scales (bool): Defaults to True. Allow scales to be parsed multiple times. The values will stack. If False, the first scale will be used and subsequent duplicates will be added to the invalid tuple.
    • prevent_thousands_extra_digits (bool): Defaults to True. Prevent thousands from being parsed if it has more than three digits following the thousand delimiter. Ex: 1,2345. The number will be added to the invalid tuple. If False, the number will be interpreted as 12,345. This does not allow for thousands to be parsed with less than three digits following the thousand delimiter.
    • allow_thousands_lacking_digits (bool): Defaults to False. If True, allow thousands to be parsed with less than three digits following the thousand delimiter. Ex: 1,23 will be interpreted as 123, or 2,455 5 as 24,555 (depending on terms in config).
  • HH:MM:SS notation (roughly).
    • It is not strictly adherent to typical HH:MM:SS standards. Any parsable numbers work in each slot, whether they are single digits, multiple digits, or include decimals.
      • For example, 2.56:27/3:270:19.2231 is a valid input in place of 2.56 days, 9 hours, 270 minutes, and 19.2231 seconds.
      • It also accepts a single connector, such as a space, between deliminators. Example: 2: 6: 3.
    • Supports up to as many segments as there are scales defined, including custom scales (10 default, Millisecond to Century).
      • The segments are parsed in reverse order, so smallest to largest (the order defined in the config and therefore the order loaded into the Locale, may differ for custom defined Scales) to ensure the correct scales are applied.
        • EXCEPTION: The default base from which HH:MM:SS starts at is Second. Any scales (typically of lesser value) listed prior in the config, or appended to the scales list before Second in the case of custom scales, will not be utilized unless Second is disabled or as many HH:MM:SS segments are parsed as there are scales defined.
        • 12:30:15 is 12 hours, 30 minutes, and 15 seconds, NOT 12 minutes, 30 seconds, and 15 milliseconds.
        • 1:10:100:12:52:30:24:60:60:1000 will make use of Century to Millisecond.
    • Delimiters are modifiable in the config under the hhmmss_delimiters key. Values must be unique from decimal_delimiters and thousand_delimiters.
  • Quickly access the parsed TimeLength as a timedelta with TimeLength().result.delta.
  • Find the relative datetime of your input in the past or future with TimeLength().ago() and TimeLength().hence().
    • Both take an optional base argument which is a datetime. It defaults to the present in UTC.
  • Have TimeLength guess the Locale by passing Guess() for the locale.
    • It will attempt to parse with all locales currently available and return the best result. The best result is the one with the least invalid results.
    • Add custom Locales by appending to Guess().locales.
    • TimeLength().locale will be set to the guessed locale.
    • Guess subsequent parses by using TimeLength().parse(guess_locale=True) or TimeLength().parse(guess_locale=Guess()).
  • Perform arithmetic operations on TimeLength objects.
    • Check the README for a full list of supported operations and types.
    • All operations not involving a datetime are absolute. For example, TimeLength("1 minute") - TimeLength("5 minutes") will return TimeLength("4 minutes").
    • Any resultant TimeLengths will inherit the locale from the first encountered TimeLength in the arithmetic.
  • Perform comparison operations on TimeLength objects.
    • Comparison based on their parsed seconds for all but bool and len comparisons.
    • bool returns if parsing succeeded based on the result.success attribute.
    • len returns the length of the passed content attribute.
  • Other things I've likely forgotten.

Improvements

  • Seconds will now only be assumed as the input if the Second scale is enabled (and assuming is enabled). If Second is disabled, the first loaded scale (typically the smallest value wise unless you have defined custom scales out of order) will be used instead.
  • Overhauled various __str__ and _repr__ functions.
  • Added full type hinting.
  • Commented areas where the reasoning for doing things is unclear (many places).
  • A lot of things are now properties to discourage modifying them.
  • Various errors added for incorrect usage.
  • Tests expanded to 100% coverage.
  • The ruff formatter now uses a line-length of 120 instead of the default 88.
  • Other things I've likely forgotten.

v2.0.5

05 Jul 12:14

Choose a tag to compare

  • Fixed an edge case with decimals that have no leading 0 (ex: .18)
  • Expanded tests to cover changes made in v2.0.3 that were unaccounted for.

v2.0.4

25 Jun 08:01

Choose a tag to compare

  • Slightly decluttered the logic of the TimeLength.parse() method.
  • Updated tests.

v2.0.3

01 Jun 11:44

Choose a tag to compare

  • Improved numeral parsing. Results from numeral input should be more accurate for larger numbers.
  • Improved Spanish parsing (probably).

v2.0.2

25 Apr 11:57

Choose a tag to compare

  • Updated outdated docstring example.
  • Various github-relevant-but-not-package-relevant changes.

v2.0.1

05 Apr 02:08

Choose a tag to compare

  • Added a few missing tests to both the English and Spanish test files that got lost during translation.
  • Modified parsing slightly to account for unconventional inputs.

v2.0.0

05 Apr 00:17

Choose a tag to compare

Rewritten to hopefully achieve a cleaner code base and better user experience.

Breaking

  • Only officially supporting Python 3.8 and above.
  • TimeLength.total_seconds was moved to TimeLength.result.seconds.
  • TimeLength.parsed_value was moved to TimeLength.result.invalid and TimeLength.result.valid.
  • TimeLength.passed_value was renamed to TimeLength.content.
  • Scales, such as TimeLength.Second, were moved to the TimeLength.Locale.

Features

  • TimeLength.result.success to determine the parsing outcome based on TimeLength.strict. See the README for more information.
  • Numerals (half a day), (twelve hours), etc, are supported.
  • The same TimeLength object can be reused by accessing TimeLength.content and TimeLength.parse().
  • Parsers are now in their own files found in timelength/parsers and are loaded dynamically by the Locale that uses them. Locales determine which parser to use based on the config file they are passed, which are found in timelength/locales.
  • The 2 default supported Locales are English and Spanish. Custom Locales are possible by using the CustomLocale object and a custom config file. See the README for more information.

Improvements

  • Errors will no longer be thrown during parsing even if TimeLength.strict is True. If "invalid" (as determined by the relevant parser) inputs are found, it will be up to the user to determine how to proceed. Errors are still thrown if the config is invalid, or if a conversion method is used for a disabled Scale.
  • Using ruff to format code everywhere except for the test files.