Relativen Anteil von zwei Datümer auf Monatsebene umrechnen

Jährlich:
Vertragsbeginn: 15.06.20 00:00
Gebührenintervall: jährlich
Gebühr: 275 Euro
Setup Gebühr: 50 Euro

1)
Endet am: 02.11.2020 um 07:10
Abgerechnet bis 15.06.21 00:00
Gutschrift: 202,07 EUR

2)
Endet am: 02.11.2020 um 00:00
Abgerechnet bis: 15.06.21 00:00
Gutschrift: 202,34 EUR
-> Gutschrift wurde mit Faktor 0,61828 berechnet

3)
Vertragsstart:
Endet am: 15.06.2020 um 00:00
Abgerechnet bis: 15.06.21 00:00
Gutschrift: 386,75 EUR

4)
Endet am: 16.06.2020
Abgerechnet bis: 15.06.21 00:00
Gutschrift: 326,35 EUR
-> Gutschrift wurde mit Faktor 0,997222 berechnet
Java:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.YearMonth;

public class Jahr {
    public static float costs(LocalDateTime start, LocalDateTime mid, LocalDateTime end, float amount1, float amount2) {
        if (start.isEqual(mid)) {
            return Math.round((amount1 + amount2) * 1.19f * 100.0f) / 100.0f;
        }
        LocalDateTime t = start;
        int m = 0;
        while (t.isBefore(mid)) {
            t = t.plusMonths(1);
            m++;
        }
        t = t.minusMonths(1);
        m--;
        float d = Duration.between(t, mid).toMinutes() / (60.0f * 24.0f);
        float f1 = amount2 * 1.19f / 12.0f;
        float f2 = d / (float) YearMonth.of(t.getYear(), t.getMonthValue()).lengthOfMonth() * f1;
        return (float) Math.ceil((f1 * 12.0f - (f1 * m + f2)) * 100.0f) / 100.0f;
    }

    public static void main(String[] args) {
        System.out.println(costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 11, 2, 7, 10), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f));
        System.out.println(costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 11, 2, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f));
        System.out.println(costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f));
        System.out.println(costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 6, 16, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f));
    }
}
 
vielen vielen Dank!!!

Wäre es noch möglich die monatlichen Beiträge in eine Liste zu packen? Siehe #95.
Den Endbetrag errechne ich dann einfach anhand der Summe der Objekte in der Liste.

Wie könnte ich hier den monatlichen Beitrag bekommen? Das müsste doch irgendwie in der while Schleife dann geschehen?
 
Zuletzt bearbeitet:
f1 ist der monatliche Betrag. Erstell eine Methode getMonAmount oder so ähnlich, der diesen Betrag zurück gibt.

Dann brauchst du eine Datenstruktur. In diese packst du den monatlichen Betrag und die Kosten. Danach kannst du die Datenstruktur/die Liste sortieren.

Oder habe ich dich falsch verstanden und du möchtest für jeden Monat die Kosten haben? 😉
 
@beta20 :
Java:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;

public class Jahr {
    public static float round(float f) {
        return Math.round(f * 100.0f) / 100.f;
    }

    public static List<List<Number>> costs(LocalDateTime start, LocalDateTime mid, LocalDateTime end, float amount1, float amount2) {
        List<List<Number>> list = new ArrayList<>();
        if (start.isEqual(mid)) {
            list.add(List.of(start.getMonthValue(), round((amount1 + amount2) * 1.19f)));
            return list;
        }
        float monAmount = round(amount2 * 1.19f / 12.0f); // Achtung: Rundungsungenauigkeiten...
        LocalDateTime t = start;
        while (t.plusMonths(1).isBefore(mid)) {
            list.add(List.of(t.getMonthValue(), monAmount));
            t = t.plusMonths(1);
        }

        float d = Duration.between(t, mid).toMinutes() / (60.0f * 24.0f);
        float dayAmount = monAmount / 31.0f;
        list.add(List.of(t.getMonthValue(), round(d * dayAmount)));
        return list;
    }

    public static void main(String[] args) {
        float yearAmount = 275.0f * 1.19f;
        System.out.println(round(yearAmount - (float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 11, 2, 7, 10), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum()));
        System.out.println(round(yearAmount - (float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 11, 2, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum()));
        System.out.println((float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum());
        System.out.println(round(yearAmount - (float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 6, 16, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum()));
    }
}
Damit wär dieser Drops gelutscht.
 
@beta20 :
Java:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;

public class Jahr {
    public static float round(float f) {
        return Math.round(f * 100.0f) / 100.f;
    }

    public static List<List<Number>> costs(LocalDateTime start, LocalDateTime mid, LocalDateTime end, float amount1, float amount2) {
        List<List<Number>> list = new ArrayList<>();
        if (start.isEqual(mid)) {
            list.add(List.of(start.getMonthValue(), round((amount1 + amount2) * 1.19f)));
            return list;
        }
        float monAmount = round(amount2 * 1.19f / 12.0f); // Achtung: Rundungsungenauigkeiten...
        LocalDateTime t = start;
        while (t.plusMonths(1).isBefore(mid)) {
            list.add(List.of(t.getMonthValue(), monAmount));
            t = t.plusMonths(1);
        }

        float d = Duration.between(t, mid).toMinutes() / (60.0f * 24.0f);
        float dayAmount = monAmount / 31.0f;
        list.add(List.of(t.getMonthValue(), round(d * dayAmount)));
        return list;
    }

    public static void main(String[] args) {
        float yearAmount = 275.0f * 1.19f;
        System.out.println(round(yearAmount - (float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 11, 2, 7, 10), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum()));
        System.out.println(round(yearAmount - (float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 11, 2, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum()));
        System.out.println((float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum());
        System.out.println(round(yearAmount - (float) costs(LocalDateTime.of(2020, 6, 15, 0, 0), LocalDateTime.of(2020, 6, 16, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f).stream().mapToDouble(l -> (Float) l.get(1)).sum()));
    }
}
Damit wär dieser Drops gelutscht.
danke dir sehr!

Wollte es gerade mal testen, bekomme aber einen Compiler Fehler:
List.of(

Liegt das an unterschiedlichen Java Versionen? Ich verwende ebenfalls: import java.util.List;
The method of(int, float) is undefined for the type List

Anstatt List<List<Number>> bräuchte ich eine Liste aus, also List<HelperClass>>
Also idealerweiße wie im Beitrag: #91

Java:
HelperClass {
   private LocalDateTime startDate; // Start von Monat
   private LocalDateTime endDate; // Ende von Monat
   private double fee; // generell die monatliche Gebühr, i.d.R. immer der gleiche Betrag
   private int days; // Anzahl an Tage, die für diesen Monat berechnet wurden
   private double monthValue; // Die berechnete Gebühr für diesen Monat
}
 
Zuletzt bearbeitet:
HelperClass ist hier nur ein temporärer Name, um zu verdeutlichen, dass er eine eigen Klasse dafür hat...

@beta20 Du müsstest das jetzt eigentlich hinbekommen, die Zwischenberechnungen stehen ja da...

Eh, List.of() ist dieser neumodische Kram aus Java 8 oder so.... aber das entfällt ja durch HelperClass
 
Danke. Habe es nun implementiert:

Java:
    public static float round(float f) {
        return Math.round(f * 100.0f) / 100.f;
    }

    public static List<ContractChangeCalculationHelper> costs(LocalDateTime start, LocalDateTime mid, LocalDateTime end,
            float amount1, float amount2) {
        List<ContractChangeCalculationHelper> list = new ArrayList<ContractChangeCalculationHelper>();

        if (start.isEqual(mid)) {

            ContractChangeCalculationHelper cObject = new ContractChangeCalculationHelper();
            cObject.setFee(amount2);
            cObject.setStartDate(start);
            cObject.setEndDate(mid);
            cObject.setValue(round((amount1 + amount2) * 1.19f));

            list.add(cObject);
            return list;
        }
        float monAmount = round(amount2 * 1.19f / 12.0f); // Achtung: Rundungsungenauigkeiten...

        LocalDateTime t = start;
        while (t.plusMonths(1).isBefore(mid)) {

            ContractChangeCalculationHelper cObject = new ContractChangeCalculationHelper();
            cObject.setFee(amount2);
            cObject.setStartDate(t);
            cObject.setEndDate(t.plusMonths(1));

            float days = Duration.between(t, cObject.getEndDate()).toDays();
            cObject.setDays((int) days);
          
            cObject.setValue(monAmount);
            list.add(cObject);

            t = t.plusMonths(1);
        }

        float d = Duration.between(t, mid).toMinutes() / (60.0f * 24.0f);
        float dayAmount = monAmount / 31.0f;
        float monthValue = round(d * dayAmount);
      
        float days = Duration.between(t, mid).toDays();

        ContractChangeCalculationHelper cObject = new ContractChangeCalculationHelper();
        cObject.setFee(amount2);
        cObject.setStartDate(t);
        cObject.setEndDate(t.plusMonths(1));
        cObject.setValue(monthValue);
        cObject.setDays((int) days);
        list.add(cObject);

        return list;
    }

    public static void main(String[] args) {

        float yearAmount = 275.0f * 1.19f;

        List<ContractChangeCalculationHelper> test = costs(LocalDateTime.of(2020, 6, 15, 0, 0),
                LocalDateTime.of(2020, 11, 2, 0, 0), LocalDateTime.of(2021, 6, 15, 0, 0), 50.0f, 275.0f);

        for (int i = 0; i <= test.size() - 1; i++) {
            ContractChangeCalculationHelper c = test.get(i);
            System.out.println(c.getStartDate() + " " + c.getEndDate() + " " + c.getValue() + " " + c.getDays());
        }

        double sum = test.stream().mapToDouble(f -> f.getValue()).sum();
        System.out.println(yearAmount - sum);
    }

Bekomme das hier raus:


StartEndeBetragAnteilig Monat
2020-06-15T00:002020-07-15T00:0027.27000045776367230
2020-07-15T00:002020-08-15T00:0027.27000045776367231
2020-08-15T00:002020-09-15T00:0027.27000045776367231
2020-09-15T00:002020-10-15T00:0027.27000045776367230
2020-10-15T00:002020-11-15T00:0016.10000038146972718

Summe: 202.34002876281738

Wenn ich nun aber die Tabelle von LimDul vergleiche ( https://www.java-forum.org/thema/re...auf-monatsebene-umrechnen.185575/post-1235634 ), dann fällt auf, dass hier das Ende auf den 14. jeweils liegt.

Ist nun an meinem Code etwas falsch?
 
Zuletzt bearbeitet:
ok, danke... Hab noch die Sekunden berücksichtigt:

Java:
cObject.setEndDate(t.plusMonths(1).minusSeconds(1));
 
23:59 Uhr ist end of business day/EOB, eigentlich ist das in elektronischen System gängig https://blog.wiwo.de/management/2018/08/23/cob-eob-und-asap-was-die-us-abuerzungen-in-mails-bedeuten/
 
so wirklich verstanden habe ich es aber nicht, warum ich den 14. und nicht den 15. nehmen sollte.
Insbesondere wenn ich noch Uhrzeiten mitnehme, zB 07:14 Uhr, dann sollte es doch:

15.06.2020 07:14 - 15.07.2020 07:14 sein?

Bei manchen Verträgen mag es sein, dass eben nur volle Tage betrachtet werden, aber zB bei SaaS - Modellen wäre die Betrachtung bis 15.07.2020 07:14 doch nicht unüblich?
 
Ich glaub, die Tabelle von @LimDul ist bezüglich der Tag-Spalte auch nicht ganz richtig. 😉

Nimm doch einfach den 15., anstatt den 14. um 23:59 Uhr...
 
Habe hier noch eine Verständnisfrage zur Monatsabrechnung:
Wenn der Kunde einen monatlichen Tarif bucht (zB für 20 EUR / Monat), dann sollte die Quantity, die auf der Rechnung steht ja immer 1 sein.

Also aus dem obigen Beispiel:
15.06.2020 07:14 - 15.07.2020 07:14
-> Anzahl 1
-> Preis 20,00 EUR / Monat

Da die Monate ja nicht immer die gleiche Anzahl an Tage haben, würde die obige Formel ja aber nicht funktionieren, es würde u.U. nicht 1 herauskommen, sondern 1,02 usw.

Die Frage ist nun:
Kann ich die obige Berechnung dafür überhaupt nehmen oder soll ich prüfen, ob es sich um eine monatliche Abrechnung handelt? Wenn ja, dann berechne die Quantity mit 1 und den monatlichen Preis von 20,00 EUR... Falls nein, dann nehme die obige Formel (ggf. muss nur anteilig vom Monat berechnet werden)?
 
So funktioniert aber in dem Beispiel das der Threadersteller hat, leider nicht. Da wird quasi der Monat immer von Tag X des Beginn-Monats bis Tag X des Folgemonats berechnet (egal wie viele Tage das sind).
Ja und daraus entstehen eben Probleme, die ich mir nicht antun würde. Was macht man beispielsweise, wenn Tag X im Folgemonat überhaupt nicht existiert? Man bräuchte also erst einmal eine Definition, was ein Monat im Sinne dieses Abrechnungsmodells überhaupt sein soll. Außerdem nerven Rechnungen mit Monats- oder Jahresübergreifendem Leistungszeitraum sowieso, weil sie Abgrenzungsbuchungen nach sich ziehen und nicht synchron zu Steuer- oder Gesetzesänderungen sind. All das könnte man vermeiden, wenn man die eigenen Rechnungen mit den Kalendermonaten synchronisiert. Bis jetzt gab es ja noch keine echten Begründungen (die es durchaus geben mag) für das Modell des TE, außer dass eine andere Software, deren Berechnungsverfahren dem TE zwar nicht bekannt ist, aber aus irgendwelchen Gründen dennoch als maßgeblich angesehen wird, es eben so macht.
 
Habe hier noch eine Verständnisfrage zur Monatsabrechnung:
Wie kann man bitte ein Verständnisproblem bzgl. der Berechnung eines Tarifs haben, den man selbst festlegt?!?

Nachtrag, damit besser rauskommt, was ich meine: nehmen wir mal an, Du vereinbarst für irgendeine Leistung einen Preis/Stunde von 60 €. Die Frage, ob Du nur ganze Stunden, jede Minute, Sekunde, Viertelstunden, angefangene Stunden, angefangene halbe Stunden usw. usw. abrechnen darfst, ist primär eine Frage Deiner Festlegungen.

Du aber sagst: hey, ich verlange 60 €/Stunde, wie rechne ich jetzt 25 Minuten? Die Frage lässt sich nicht beantworten, denn das ist abhängig vom Rechenweg (d. h. ob und in welcher Form Du anteilig die Stunden berechnen darfst), den Du festlegen musst.
 
Zuletzt bearbeitet:
Ich glaube wir reden hier von zwei Paar Schuhen.
1) Der obere Code traf eher bei Vertragswechsel / Upgrade / Kündigung zu.

Bei meiner letzten Frage bzgl. monatliche Abrechnung scheint mir die Abrechnung eine andere zu sein.

Hier mal ein paar Beispiele (monatlich):
1) Vertragsbeginn: am 29.02.2020 00:00
Rechnung1: 29.2.2020, 00:00 - 28.3.2020, 23:59
Rechnung2: 29.3.2020, 00:00 - 28.4.2020, 23:59
Rechnung3: 29.4.2020, 00:00 - 28.5.2020, 23:59
Rechnung4: 29.5.2020, 00:00 - 28.6.2020, 23:59
Rechnung5: 29.6.2020, 00:00 - 28.7.2020, 23:59

2) Vertragsbeginn: am 31.01.2020 00:00
Rechnung1: 31.1.2020, 00:00 - 28.2.2020, 23:59
Rechnung2: 29.2.2020, 00:00 - 30.3.2020, 23:59
Rechnung3: 31.3.2020, 00:00 - 29.4.2020, 23:59
Rechnung4: 30.4.2020, 00:00 - 30.5.2020, 23:59

3) Vertragsbeginn: am 31.01.2020 23:28
Rechnung1: 31.1.2020, 23:28 - 29.2.2020, 23:28
Rechnung2: 29.2.2020, 23:28 - 31.3.2020, 23:28
Rechnung3: 31.3.2020, 23:28 - 30.4.2020, 23:28
Rechnung4: 30.4.2020, 23:28 - 31.5.2020, 23:28

Das heißt aber, dass bei 2) / 3) zB nicht einfach der Monat addiert wird, sondern der Tag genommen wird, an dem der Vertrag startet?!
Java:
        LocalDateTime test1 = LocalDateTime.of(2020, 1, 31, 0, 0);
        LocalDateTime test2 = test1.plusMonths(1);
        LocalDateTime test3 = test2.plusMonths(1);

2020-02-29T00:00
2020-03-29T00:00

Frage:
Gibt es in der neuen java.time API solch eine Methode, die mir immer zB den 31. von jedem Monat holt und falls es diesen Tag nicht gibt den vorherigen Tag und falls es den auch nicht gibt (Schaltjahr), den vorvorherigen Tag zurückgibt? Falls ja, wie?

Jährlich sieht es so aus:
4) Vertragsbeginn: am 29.02.2020 00:00
Erste Rechnung: 29.2.2020, 00:00 - 27.2.2021, 23:59

5) Vertragsbeginn: am 31.01.2020 00:00
Erste Rechnung: 31.1.2020, 00:00 - 30.1.2021, 23:59

6) Vertragsbeginn: am 31.01.2020 23:35
Erste Rechnung: 31.1.2020, 23:35 - 31.1.2021, 23:35

-> Hier sieht es für mich aus, dass folgendes berechnet wird:
Java:
test1.plusYears(1);
 
Wie kann man bitte ein Verständnisproblem bzgl. der Berechnung eines Tarifs haben, den man selbst festlegt?!?

Nachtrag, damit besser rauskommt, was ich meine: nehmen wir mal an, Du vereinbarst für irgendeine Leistung einen Preis/Stunde von 60 €. Die Frage, ob Du nur ganze Stunden, jede Minute, Sekunde, Viertelstunden, angefangene Stunden, angefangene halbe Stunden usw. usw. abrechnen darfst, ist primär eine Frage Deiner Festlegungen.

Du aber sagst: hey, ich verlange 60 €/Stunde, wie rechne ich jetzt 25 Minuten? Die Frage lässt sich nicht beantworten, denn das ist abhängig vom Rechenweg (d. h. ob und in welcher Form Du anteilig die Stunden berechnen darfst), den Du festlegen musst.
gebe ich dir natürlich vollkommen Recht, absolut keine Frage. Ich versuche mich nur gerade an etwas bestehendem zu orentieren.
 
Frage:
Gibt es in der neuen java.time API solch eine Methode, die mir immer zB den 31. von jedem Monat holt und falls es diesen Tag nicht gibt den vorherigen Tag und falls es den auch nicht gibt (Schaltjahr), den vorvorherigen Tag zurückgibt? Falls ja, wie?
XY-Problem 😉 es gibt eine, die dir den letzten Tag des Monats gibt: date.with(TemporalAdjusters.lastDayOfMonth())
 
ok, dann müsste ich eigentlich prüfen:

a) Gibt es den Tag im nächsten Monat, dann diesen nehmen
b) Tag gibt es nicht im nächsten Monat, dann date.with(TemporalAdjusters.lastDayOfMonth())

Oder liege ich falsch?
 
Gibt ja viele Varianten. Wenn es nur darum geht eine fremde Rechnung nachzuvollziehen, muss man das halt nachbauen.

Aber wenn man - wo es jetzt fast nach aussieht - selber Rechnungen schreiben will, finde ich das sehr gefährlich. Wenn man selber nicht versteht, was man tut und wie es sich berechnet, wie will man das dem Kunden erklären und was sagt eigentlich der Steuerberater dazu?
 

Neue Themen


Zurück
Oben