[GELÖST] FHEM: falsch, Perl-Online-Editor: richtig - Warum?

Begonnen von DocCyber, 25 März 2024, 19:08:58

Vorheriges Thema - Nächstes Thema

Christoph Morrison

LANG=de_DE.UTF-8:
Ultimo letzter Tag: 30.03.24
Ultimo letzter Werktag: 30.03.24

Falsch.

LANG=C:
Ultimo letzter Tag: 30.03.24
Ultimo letzter Werktag: 29.03.24

Falsch.

So sieht's bei mir aus. Meine Vermutung gerade: Es hat mit locale und TZ zu tun. Ich hab mir mal die berechneten Timestamps angeguckt und siehe da:

LANG=de_DE.UTF-8, TZ=CET
Ultimo letzter Tag: 30.03.24
Ultimo letzter Werktag: 30.03.24

Wird wärmer.

LANG=de_DE.UTF-8, TZ=UTC
Ultimo letzter Tag: 30.03.24
Ultimo letzter Werktag: 29.03.24

Mhm.

LANG=C, TZ=UTC
Ultimo letzter Tag: 31.03.24
Ultimo letzter Werktag: 29.03.24

Und das ist der Gewinner.

DocCyber

Zitat von: Christoph Morrison am 26 März 2024, 17:06:53LANG=C, TZ=UTC
Ultimo letzter Tag: 31.03.24
Ultimo letzter Werktag: 29.03.24

Und das ist der Gewinner.

Die Antwort ist also ganz und gar nicht trivial, und ich hätte sie vermutlich nie herausgefunden.
Vielen Dank!


(Kleine Nachbemerkung: Zugegeben - der Code ist nicht gerade als elegant zu bezeichnen. Zu meiner Entschuldigung kann ich nur sagen, dass es nicht "mein" Code ist, sondern ich habe ihn wie erwähnt im Netz gefunden.
Aber es ging ja auch nicht um den Code als solchen, sondern um die Fragestellung, warum er unterschiedliche Resultate liefert. Denn es kann nicht sein, dass ein Code gleichzeitig falsch und richtig ist.)
Behandle die Menschen so, als wären sie, was sie sein sollten. Dadurch hilfst du ihnen zu werden, was sie sein können. (Goethe)


RPi-3 mit HM-CFG-LAN und jede Menge HM Komponenten.

Christoph Morrison

#17
Ich war mal so frei und habe eine bessere Version von ultimo geschrieben, die unabhängig von Timezone, Locale und zusätzlichen Modulen ist:

use constant {
    ONLY_EOM          => 0,  # only last day of a month
    CONSIDER_WEEKENDS => 1,  # consider weekends in calculation
};

sub ultimo {
    use Time::Piece;   # core ≥ v5.9.5
    use List::Util;    # core ≥ v5.7.3
    use warnings;      # core ≥ v5.6.0
    use Carp;          # core ≥ v5
    use strict;        # core ≥ v5

    my $time_piece_object = localtime;

    my $consider_modifications  = shift || ONLY_EOM;
    my $year                    = shift || $time_piece_object->year;
    my $month                   = shift || $time_piece_object->mon;

    if (! List::Util::any { $_ == $consider_modifications } ( CONSIDER_WEEKENDS, ONLY_EOM ) ) {
        carp("$consider_modifications is not a valid value. Resetting to " . ONLY_EOM);
        $consider_modifications = ONLY_EOM;
    }

    # set calculation base to year-month-date
    my $calc_base_date = $time_piece_object->strptime("$year-$month-1", '%Y-%m-%d');

    # eom = End of Month
    my $eom = $calc_base_date->month_last_day;

    # don't consider workdays, just the eom
    if ($consider_modifications == 0) {
        return $eom;
    }

    # set Timme::Pice to current last month day
    $calc_base_date = $time_piece_object->strptime("$year-$month-$eom", '%Y-%m-%d');

    # substract two days if the eom day is a sunday
    if ($calc_base_date->wday == 1) {
        return $eom - 2;
    }

    # substract one day if the eom day is a saturday
    if ($calc_base_date->wday == 7) {
        return $eom - 1;
    }
}

Die Funktion unterstützt neben ONLY_EOM (Ende des Monats ohne Abzüge) auch CONSIDER_WEEKENDS als Parameter (Samstage sind je nach Gesetz Werktage oder auch nicht, aber immer Wochenende).

Außerdem kannst du mit dem zweiten Parameter ein Jahr angeben und mit dem dritten Parameter einen Monat, so kannst du auch für andere Monate als für den aktuellen das Monatsende bestimmen. Beispiele:

# heute = 26.03.2024
ultimo(ONLY_EOM)            = 31
identisch zu
ultimo(ONLY_EOM, 2024, 3)  = 31
ultimo(CONSIDER_WEEKENDS);  = 29

In der Zukunft:
ultimo(ONLY_EOM, 2024, 6);  = 30
ultimo(CONSIDER_WEEKENDS, 2024, 6);  = 28

In der Vergangenheit:
ultimo(ONLY_EOM, 2023, 12)  = 31
ultimo(CONSIDER_WEEKENDS, 2023, 12)  = 29

betateilchen

Zitat von: Otto123 am 26 März 2024, 16:26:24at_ultimo liefert übrigens die letzte Minute des Monats

Aber nur, wenn Du nichts anderes angibst.

{at_ultimo(12,34,56)}
liefert nicht die letzte Minute des Monats.

ZitatTo execute a FHEM command on every last day of the month,
the function at_ultimo() can be used as perlfunc for datespec.
define at_ultimo at *{at_ultimo()} set lamp1 off
This will create an at device which will be executed at 23:59:00 on the last day of month.
at_ultimo() can take additional parameters to specify an other time on this day
define at_ultimo at *{at_ultimo(12,23,45)} set lamp1 off
This will create an at device which will be executed ad 12:34:45 on the last day of month.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

DocCyber

Zitat von: Christoph Morrison am 26 März 2024, 21:35:40Ich war mal so frei und habe eine bessere Version von ultimo geschrieben, die unabhängig von Timezone, Locale und zusätzlichen Modulen ist
Klasse - sehr professionell! Danke!
Behandle die Menschen so, als wären sie, was sie sein sollten. Dadurch hilfst du ihnen zu werden, was sie sein können. (Goethe)


RPi-3 mit HM-CFG-LAN und jede Menge HM Komponenten.