Frage

Ich habe einige Code, der die Oracle-Funktion ADD_MONTHS verwendet ein Datum von X Anzahl der Monate zu erhöhen.

Ich brauche jetzt die gleiche Logik in einer C / C ++ Funktion neu zu implementieren. Aus Gründen möchte ich nicht / muss gehen in ich nicht einfach eine Abfrage an Oracle ausgeben kann das neue Datum zu erhalten.

Kennt jemand eine einfache und zuverlässige Art und Weise X Anzahl von Monaten zu einem time_t hinzuzufügen? Einige Beispiele für die Arten von Berechnungen weiter unten.

30.01.2009 + 1 Monat = 28.02.2009
31.01.2009 + 1 Monat = 28.02.2009
27.02.2009 + 1 Monat = 27.03.2009
28.02.2009 + 1 Monat = 31.03.2009
31.01.2009 + 50 Monate = 31.03.2013

War es hilfreich?

Lösung

Methode AddMonths_OracleStyle das tut, was Sie brauchen.

Vielleicht möchten Sie IsLeapYear und GetDaysInMonth einigen Bibliothekar Methoden ersetzen.

#include <ctime>
#include <assert.h>

bool IsLeapYear(int year) 
{
    if (year % 4 != 0) return false;
    if (year % 400 == 0) return true;
    if (year % 100 == 0) return false;
    return true;
}

int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int GetDaysInMonth(int year, int month)
{
    assert(month >= 0);
    assert(month < 12);

    int days = daysInMonths[month];

    if (month == 1 && IsLeapYear(year)) // February of a leap year
        days += 1;

    return days;
}

tm AddMonths_OracleStyle(const tm &d, int months)
{
    bool isLastDayInMonth = d.tm_mday == GetDaysInMonth(d.tm_year, d.tm_mon);

    int year = d.tm_year + months / 12;
    int month = d.tm_mon + months % 12;

    if (month > 11)
    {
        year += 1;
        month -= 12;
    }

    int day;

    if (isLastDayInMonth)
        day = GetDaysInMonth(year, month); // Last day of month maps to last day of result month
    else
        day = std::min(d.tm_mday, GetDaysInMonth(year, month));

    tm result = tm();

    result.tm_year = year;
    result.tm_mon = month;
    result.tm_mday = day;

    result.tm_hour = d.tm_hour;
    result.tm_min = d.tm_min;
    result.tm_sec = d.tm_sec;

    return result;
}

time_t AddMonths_OracleStyle(const time_t &date, int months)
{
    tm d = tm();

    localtime_s(&d, &date);

    tm result = AddMonths_OracleStyle(d, months);

    return mktime(&result);
}

Andere Tipps

Sie können mit Boost.GregorianDate hierfür.

Insbesondere bestimmen den Monat, indem die korrekte Zugabe von date_duration , und verwenden Sie dann end_of_month_day() von dem Zeitpunkt Algorithmen

Konvertieren time_t struct tm, fügen X zu Monat, fügen Monate> 12 Jahre zurück zu konvertieren. tm.tm_mon ist ein int, das Hinzufügen 32000+ Monate sollte kein Problem sein.

[Bearbeiten] Vielleicht finden Sie, dass Oracle passende heikel ist, wenn Sie auf die härteren Fälle zu bekommen, wie das Hinzufügen von 12 Monaten 29.02.2008. Sowohl 01.03.2009 und 28.02.2008 sind angemessen.

wirklich neue Antwort auf eine wirklich alte Frage!

Mit dieser freien und Open-Source-Bibliothek und ein C ++ 14-Compiler (wie Klappern) das kann ich jetzt schreiben:

#include "date.h"

constexpr
date::year_month_day
add(date::year_month_day ymd, date::months m) noexcept
{
    using namespace date;
    auto was_last = ymd == ymd.year()/ymd.month()/last;
    ymd = ymd + m;
    if (!ymd.ok() || was_last)
        ymd = ymd.year()/ymd.month()/last;
    return ymd;
}

int
main()
{
    using namespace date;
    static_assert(add(30_d/01/2009, months{ 1}) == 28_d/02/2009, "");
    static_assert(add(31_d/01/2009, months{ 1}) == 28_d/02/2009, "");
    static_assert(add(27_d/02/2009, months{ 1}) == 27_d/03/2009, "");
    static_assert(add(28_d/02/2009, months{ 1}) == 31_d/03/2009, "");
    static_assert(add(31_d/01/2009, months{50}) == 31_d/03/2013, "");
}

Und es kompiliert wird.

Beachten Sie die bemerkenswerte Ähnlichkeit zwischen dem Ist-Code und die der OP Pseudo-Code:

  

30.01.2009 + 1 Monat = 28.02.2009
  31.01.2009 + 1 Monat = 28.02.2009
  27.02.2009 + 1 Monat = 27.03.2009
  28.02.2009 + 1 Monat = 31.03.2009
  31.01.2009 + 50 Monate = 31.03.2013

Beachten Sie auch, dass die Compiler-Informationen in führt Informationen zu Zeit zu kompilieren aus .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top