diff --git a/docs/source/Reference/sr3_options.7.rst b/docs/source/Reference/sr3_options.7.rst index 74bdd96d3..8a213e2c6 100644 --- a/docs/source/Reference/sr3_options.7.rst +++ b/docs/source/Reference/sr3_options.7.rst @@ -234,7 +234,7 @@ count, size duration a floating point number indicating a quantity of seconds (0.001 is 1 milisecond) - modified by a unit suffix ( m-minute, h-hour, w-week ) + modified by a unit suffix ( m-minute, h-hour, M-month, y-year ) flag an option that has only True or False values (aka: a boolean value) @@ -798,10 +798,10 @@ expire (default: 5m == five minutes. RECOMMEND OVERRIDING) The **expire** option is expressed as a duration... it sets how long should live a queue without connections. -A raw integer is expressed in seconds, if the suffix m,h,d,w -are used, then the interval is in minutes, hours, days, or weeks. After the queue expires, +A raw integer is expressed in seconds, if the suffix m,h,d,M +are used, then the interval is in minutes, hours, days, or months. After the queue expires, the contents are dropped, and so gaps in the download data flow can arise. A value of -1d (day) or 1w (week) can be appropriate to avoid data loss. It depends on how long +1d (day) or 1m (month) can be appropriate to avoid data loss. It depends on how long the subscriber is expected to shutdown, and not suffer data loss. if no units are given, then a decimal number of seconds can be provided, such as @@ -809,7 +809,7 @@ to indicate 0.02 to specify a duration of 20 milliseconds. The **expire** setting must be overridden for operational use. The default is set low because it defines how long resources on the broker will be assigned, -and in early use (when default was 1 week) brokers would often get overloaded with very +and in early use (when default was 1 month) brokers would often get overloaded with very long queues for left-over experiments. This *subtopic* option should appear after the *expire* setting in files @@ -1304,10 +1304,10 @@ process looks for files in the cache that have not been referenced in **cache** and deletes them, in order to keep the cache size limited. Different settings are appropriate for different use cases. -A raw integer interval is in seconds, if the suffix m,h,d, or w are used, then the interval -is in minutes, hours, days, or weeks. After the interval expires the contents are +A raw integer interval is in seconds, if the suffix m,h,d, or M are used, then the interval +is in minutes, hours, days, or months. After the interval expires the contents are dropped, so duplicates separated by a large enough interval will get through. -A value of 1d (day) or 1w (week) can be appropriate. Setting the option without specifying +A value of 1d (day) or 1M (Month) can be appropriate. Setting the option without specifying a time will result in 300 seconds (or 5 minutes) being the expiry interval. Default value in a Poll is 8 hours, should be longer than nodupe_fileAgeMax to prevent diff --git a/docs/source/fr/Reference/sr3_options.7.rst b/docs/source/fr/Reference/sr3_options.7.rst index 72e16accc..51713b3f2 100644 --- a/docs/source/fr/Reference/sr3_options.7.rst +++ b/docs/source/fr/Reference/sr3_options.7.rst @@ -232,7 +232,7 @@ count duration un nombre à virgule flottante qui indique une quantité en secondes (0.001 est 1 milliseconde) - modifié par un suffixe unitaire ( m-minute, h-heure, w-semaine ). + modifié par un suffixe unitaire ( m-minute, h-heure, M-mois ). flag une option qui a la valeur soit Vrai (True ou on) ou Faux (False ou off) (une valeur booléenne). @@ -786,10 +786,10 @@ expire (défaut: 5m == cinq minutes. RECOMMENDE DE REMPLACER) L'option *expire* est exprimée sous forme d'une duration... ça fixe combien de temps une fil d’attente devrait vivre sans connexions. -Un entier brut est exprimé en secondes, et si un des suffixe m,h,d,w est utilisés, l’intervalle est en minutes, -heures, jours ou semaines respectivement. Après l’expiration de la fil d’attente, le contenu est supprimé et +Un entier brut est exprimé en secondes, et si un des suffixe m,h,d,m est utilisés, l’intervalle est en minutes, +heures, jours ou mois respectivement. Après l’expiration de la fil d’attente, le contenu est supprimé et des différences peuvent donc survenir dans le flux de données de téléchargement. Une valeur de -1d (jour) ou 1w (semaine) peut être approprié pour éviter la perte de données. Cela dépend de combien de temps +1d (jour) ou 1m (mois) peut être approprié pour éviter la perte de données. Cela dépend de combien de temps l’abonné est sensé s’arrêter et ne pas subir de perte de données. Si aucune unité n’est donnée, un nombre décimal de secondes peut être fourni, tel que @@ -797,7 +797,7 @@ Si aucune unité n’est donnée, un nombre décimal de secondes peut être four Le paramètre **expire** doit être remplacé pour une utilisation opérationnelle. Le défaut est défini par une valeur basse car il définit combien de temps les ressources vont être -assigné au courtier, et dans les premières utilisations (lorsque le défaut était de de 1 semaine), les courtiers +assigné au courtier, et dans les premières utilisations (lorsque le défaut était de de 1 mois), les courtiers étaient souvent surchargés de très longues files d’attente pour les tests restants. l´option *subtopic* devrait apparaître après le paramètre *expire* dans les fichiers diff --git a/sarracenia/__init__.py b/sarracenia/__init__.py index 261a35dd8..5436dcfc5 100755 --- a/sarracenia/__init__.py +++ b/sarracenia/__init__.py @@ -316,28 +316,51 @@ def timev2tov3str(s): else: return s[0:8] + 'T' + s[8:] +""" + So for natural delta, tested stuff, and empirically it looks like humanize thinks this is how many days there are in a month. + At least assuming that makes calculations here match with what humanize does. + +""" +days_in_a_month=30.7 + def durationToString(d) -> str: """ given a numbner of seconds, return a short, human readable string. + + naturaldelta does not do weeks... """ if (d < 60): return f"{d:7.2f}s" - first_part= humanize.naturaldelta(d).replace("minutes","m").replace("seconds","s").replace("hours","h").replace("days","d").replace("an hour","1h").replace("a day","1d").replace("a minute","1m").replace(" ","") - - second_part="" - if first_part[-1] == 'm': - rem=int(d-int(first_part[0:-1])*60) - if rem > 0: - second_part=f"{rem:d}s" - if first_part[-1] == 'h': - rem=int(( d-int(first_part[0:-1])*60*60 ) / 60 ) - if rem > 0: - second_part=f"{rem:d}m" - if first_part[-1] == 'd': - rem=int (( d-int(first_part[0:-1])*60*60*24 ) / (60*60) ) - if rem > 0: - second_part=f"{rem:d}h" + hnd = humanize.naturaldelta(d).replace("minute","m").replace("second","T").replace("hour","h").replace("day","d").replace("month","M").replace("year","y").replace(" ","").replace("s","").replace("T","s").replace("an", "1").replace("a","1") + + if ',' in hnd: + ( first_part, second_part ) = hnd.split(',') + else: + first_part=hnd + second_part="" + + if not second_part: + if first_part[-1] == 'm': + rem=int(d-int(first_part[0:-1])*60) + if rem > 0: + second_part=f"{rem:d}s" + if first_part[-1] == 'h': + rem=int(( d-int(first_part[0:-1])*60*60 ) / 60 ) + if rem > 0: + second_part=f"{rem:d}m" + if first_part[-1] == 'd': + rem=int (( d-int(first_part[0:-1])*60*60*24 ) / (60*60) ) + if rem > 0: + second_part=f"{rem:d}h" + if first_part[-1] == 'M': + rem=int (( d-int(first_part[0:-1])*60*60*24*days_in_a_month ) / (60*60*24) ) + if rem > 0: + second_part=f"{rem:d}d" + if first_part[-1] == 'y': + rem=int (( d-int(first_part[0:-1])*60*60*24*365.25 ) / (60*60*24*days_in_a_month ) ) + if rem > 0: + second_part=f"{rem:d}M" return first_part+second_part def durationToSeconds(str_value, default=None) -> float: @@ -364,7 +387,7 @@ def durationToSeconds(str_value, default=None) -> float: return float(default) first_unit=None - second_unit=str_value[-1].lower() + second_unit=str_value[-1] if second_unit in 's': factor *= 1 first_unit='m' @@ -376,9 +399,24 @@ def durationToSeconds(str_value, default=None) -> float: first_unit='d' elif second_unit in 'd': factor *= 60 * 60 * 24 - first_unit='w' + if 'y' in str_value: + first_unit='y' + elif 'M' in str_value: + first_unit='M' + else: + first_unit='w' elif second_unit in 'w': factor *= 60 * 60 * 24 * 7 + if 'y' in str_value: + first_unit='y' + elif 'M' in str_value: + first_unit='M' + elif second_unit in 'M': + factor *= 60 * 60 * 24 * days_in_a_month + if 'y' in str_value: + first_unit='y' + elif second_unit in 'y': + factor *= 60 * 60 * 24 * 365.25 if str_value[-1].isalpha(): str_value = str_value[:-1] @@ -394,6 +432,10 @@ def durationToSeconds(str_value, default=None) -> float: big = big*60*60*24 elif first_unit == 'w': big = big*60*60*24*7 + elif first_unit == 'M': + big = big*60*60*24*days_in_a_month + elif first_unit == 'y': + big = big*60*60*24*365.25 str_value = little else: big=0 diff --git a/tests/sarracenia/__init___test.py b/tests/sarracenia/__init___test.py index 64f6fb2dc..e010098b0 100644 --- a/tests/sarracenia/__init___test.py +++ b/tests/sarracenia/__init___test.py @@ -32,12 +32,11 @@ def test_durationToSeconds(): assert sarracenia.durationToSeconds('none') == sarracenia.durationToSeconds('off') == sarracenia.durationToSeconds('false') == 0.0 assert sarracenia.durationToSeconds('on', default=10) == sarracenia.durationToSeconds('true', default=10) == 10.0 - assert sarracenia.durationToSeconds('1s') == sarracenia.durationToSeconds('1S') == 1.0 - assert sarracenia.durationToSeconds('2m') == sarracenia.durationToSeconds('2M') == 120.0 - assert sarracenia.durationToSeconds('3h') == sarracenia.durationToSeconds('3H') == 10800.0 - assert sarracenia.durationToSeconds('4d') == sarracenia.durationToSeconds('4D') == 345600.0 - assert sarracenia.durationToSeconds('1w') == sarracenia.durationToSeconds('1W') == 604800.0 - assert sarracenia.durationToSeconds('0.5h') == sarracenia.durationToSeconds('0.5H') == 1800.0 + assert sarracenia.durationToSeconds('1s') == 1.0 + assert sarracenia.durationToSeconds('2m') == 120.0 + assert sarracenia.durationToSeconds('3h') == 10800.0 + assert sarracenia.durationToSeconds('4d') == 345600.0 + assert sarracenia.durationToSeconds('0.5h') == 1800.0 assert sarracenia.durationToSeconds('invalid') == 0.0 assert sarracenia.durationToSeconds(b'5') == 0.0 @@ -45,11 +44,21 @@ def test_durationToSeconds(): assert sarracenia.durationToSeconds(2.5) == 2.5 assert sarracenia.durationToSeconds('1s', default=None) == 1.0 - assert sarracenia.durationToSeconds('1y') == 1.0 assert sarracenia.durationToSeconds('-1s') == -1.0 assert sarracenia.durationToSeconds('-1.5h') == -5400.0 + assert sarracenia.durationToSeconds('1w') == 24*3600*7 assert sarracenia.durationToSeconds('2h2m') == 7320 assert sarracenia.durationToSeconds('3m2s') == 182 + assert sarracenia.durationToSeconds( '6w1d' ) == 24*3600*(6*7.0+1) + assert sarracenia.durationToSeconds( '6M1d' ) == 16001280 + assert sarracenia.durationToSeconds( '6M5d' ) == round( (6*30.7+5)*24*3600 ) # the math came out .99999 ... + assert sarracenia.durationToSeconds( '1y' ) == 365.25*24*3600 + assert sarracenia.durationToSeconds( '1y28d' ) == (365.25+28)*24*3600 + assert sarracenia.durationToSeconds( '1y1M' ) == (365.25+30.7)*24*3600 + assert sarracenia.durationToSeconds( '1000w' ) == 1000*7*24*3600 + assert sarracenia.durationToSeconds( '11y' ) == 11*365.25*24*3600 + + def test_durationToString(): assert sarracenia.durationToString( 3600 ) == '1h' @@ -58,6 +67,14 @@ def test_durationToString(): assert sarracenia.durationToString( 6*3600 ) == '6h' assert sarracenia.durationToString( 6*3600+120 ) == '6h2m' assert sarracenia.durationToString( 26*3600+120 ) == '1d2h' + assert sarracenia.durationToString( 30*24*3600 ) == '30d' + assert sarracenia.durationToString( 35*24*3600 ) == '1M4d' + assert sarracenia.durationToString( 182*24*3600 ) == '5M28d' + assert sarracenia.durationToString( 186*24*3600 ) == '6M1d' + assert sarracenia.durationToString( 190*24*3600 ) == '6M5d' + assert sarracenia.durationToString( 365*24*3600 ) == '1y' + assert sarracenia.durationToString( 393*24*3600 ) == '1y28d' + assert sarracenia.durationToString( 396*24*3600 ) == '1y1M' def test_timeValidate(): assert sarracenia.timeValidate('20230710120000') == True