Search code examples
timestampunix-timestamp

timestamp - get timestamp for 01/01/2017


I have my current timestamp: 1491044139 which is 04/01/2017 @ 10:53am (UTC).

I'm trying to calculate 01/01/2017 from it (i.e. 1st of Jan of the current timestamp's year).

function getJan1stTimestamp(_timestamp){
    return (_timestamp-(_timestamp%(365*24*3600)));
}

But it keeps returning 1482192000! This is 12/20/2016 @ 12:00am (UTC) and not 01/01/2017 @ 00:00 (UTC)

I think I'm doing something very silly, but I don't know what it is ;(

I'm on a very primitive system so I can't use high level date functions and must use basic arithmetic.

**Edit: just realised I didn't post the solution...

Here it is:

uint currentYear=floor(1970+(current_timestamp/(365.25*24*3600)));   //Swallowed the 0.25s by rounding ;)
uint nLeapYears=floor((currentYear-1972)/4);   //again, rounded ;) 1972 is the first leap year after 1970
uint nNonLeapYears=currentYear-1970-nLeapYears;
uint firstJanTimestamp=nLeapYears*366*24*3600 + nNonLeapYears*365*24*3600 + 24*3600;   //added one day for good measure ;)
return firstJanTimestamp;

All of the above is done with very primitive operators (I was doing this for use in Solidity - note: in Solidity you won't need floor(...) as your decimal places will be automatically lost).

With thanks for everyone's help ;)


Solution

  • I have my current timestamp: 1491044139 which is 04/01/2017 @ 10:53am (UTC).

    1491044139 is 2017-04-01 10:55:39 UTC.

    I'm trying to calculate 01/01/2017 from it:

    01/01/2017 is 1483228800.

    But it keeps returning 1482192000! This is 12/20/2016 @ 12:00am (UTC)

    Correct.

    Here are algorithms to convert y-m-d triples to a count of days since 1970-01-01, and vice versa. Once you have a count of days you can multiply/divide by 86400 (24*3600) to get seconds. This does of course neglect leap seconds, but so does Unix Time, so this is consistent.

    The algorithms are written in C++14, but they are short and simple enough that they should be easily ported to any language. Detailed description of how these algorithms work, and unit tests for them spanning +/- millions of years are at the link.

    template <class Int>
    constexpr
    Int
    days_from_civil(Int y, unsigned m, unsigned d) noexcept
    {
        static_assert(std::numeric_limits<unsigned>::digits >= 18,
                 "This algorithm has not been ported to a 16 bit unsigned integer");
        static_assert(std::numeric_limits<Int>::digits >= 20,
                 "This algorithm has not been ported to a 16 bit signed integer");
        y -= m <= 2;
        const Int era = (y >= 0 ? y : y-399) / 400;
        const unsigned yoe = static_cast<unsigned>(y - era * 400);      // [0, 399]
        const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1;  // [0, 365]
        const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]
        return era * 146097 + static_cast<Int>(doe) - 719468;
    }
    
    template <class Int>
    constexpr
    std::tuple<Int, unsigned, unsigned>
    civil_from_days(Int z) noexcept
    {
        static_assert(std::numeric_limits<unsigned>::digits >= 18,
                 "This algorithm has not been ported to a 16 bit unsigned integer");
        static_assert(std::numeric_limits<Int>::digits >= 20,
                 "This algorithm has not been ported to a 16 bit signed integer");
        z += 719468;
        const Int era = (z >= 0 ? z : z - 146096) / 146097;
        const unsigned doe = static_cast<unsigned>(z - era * 146097);          // [0, 146096]
        const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;  // [0, 399]
        const Int y = static_cast<Int>(yoe) + era * 400;
        const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100);                // [0, 365]
        const unsigned mp = (5*doy + 2)/153;                                   // [0, 11]
        const unsigned d = doy - (153*mp+2)/5 + 1;                             // [1, 31]
        const unsigned m = mp + (mp < 10 ? 3 : -9);                            // [1, 12]
        return std::tuple<Int, unsigned, unsigned>(y + (m <= 2), m, d);
    }