1

How can I extract a date (YYYY-MM-DD) from a timestamp and save it as a timestamp?
We know that 1518038663000 is Wednesday, 7 February 2018 16:24:23(GTM -5 hours) yet I would like to keep just Wednesday, 7 February 2018(GTM -5 hours) and save it as 1517979600000

Zatt
  • 33
  • 4

2 Answers2

1

If you are willing to use this free, open-source time zone library, this can be done like so:

#include "date/tz.h"
#include <iostream>

int
main()
{
    using namespace std::chrono;
    using date::operator<<;

    // set up the timestamp
    date::sys_time<milliseconds> ts{1518038663000ms};

    // create a zoned_time by pairing the timestamp with a time_zone
    auto zt = date::make_zoned("America/New_York", ts);

    // confirm what you have by printing out the timestamp and the local time
    std::cout << zt.get_sys_time().time_since_epoch() << '\n';
    std::cout << date::format("%A, %e %B %Y %T (%z)", zt) << "\n\n";

    // Truncate the zoned_time to the beginning of the local day
    zt = date::floor<date::days>(zt.get_local_time());

    // confirm what you have by printing out the timestamp and the local time
    std::cout << zt.get_sys_time().time_since_epoch() << '\n';
    std::cout << date::format("%A, %e %B %Y %T (%z)", zt) << '\n';
}

The comments in the code above describe what each line of code is doing. The single line of code in the middle is the actual answer to this question:

    // Truncate the zoned_time to the beginning of the local day
    zt = date::floor<date::days>(zt.get_local_time());

This program outputs:

1518038663000ms
Wednesday,  7 February 2018 16:24:23.000 (-0500)

1517979600000ms
Wednesday,  7 February 2018 00:00:00.000 (-0500)
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
0

Obviously random numbers said to be timestamps only have value if they also have units. For the number "1518038663000" to equate to "Wednesday, 7 February 2018 16:24:23" it implies that we are working in milliseconds since the epoch. Given such units we can convert the timestamp to 's chrono::duration: const chrono::milliseconds ts(1518038663000);

From chrono::milliseconds we'll need to cast to a chrono::duration representing days. Unfortunately the chrono library's convenience function with the longest period is hours thus we'll need to define our own chrono::duration. Since the period is defined as:

The number of seconds per tick

We'll need to calculate the number of seconds in a day, unfortunately that's not defined in the standard, but we can calculate it: ratio<86400> (or to be more explicit: ratio_multiply<chrono::hours::period, ratio<24>>).

Next we'll need to decide the rounding we want to use: What's the Difference Between floor and duration_cast? But it's probably chrono::floor. So we'll truncate to days then convert back to milliseconds to store the value:

const auto result = chrono::duration_cast<chrono::milliseconds>(chrono::floor<chrono::duration<int, ratio<86400>>>(ts))

As far as output formatting for result you'll want to use put_time which means you'll need to convert as follows:

const auto time = chrono::system_clock::to_time_t(chrono::system_clock::time_point(result));

cout << put_time(localtime(&time), "%A,%e %B %Y");

The timestamp that you'll want to store will be: result.count().

Live Example

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • If the input to your program is 1518038663000, is the output 1517979600000? If not, what is the nature of the discrepancy between what you output, and what the OP reports? – Howard Hinnant Feb 08 '18 at 15:12
  • 1
    @HowardHinnant Since you know more about this library than I do, I assume you are pointing out a potential pitfall with depending simply upon the standard. My clamp to days is absolute, it doesn't consider a GMT offset. If such an offset needs to be preserved it will need to be added back in. That's really as simple as doing `+ chrono::hours(5)`, so your `result` calculation would become: `const auto result = chrono::duration_cast(chrono::floor>>(ts)) + chrono::hours(5)`: http://coliru.stacked-crooked.com/a/27ae602bdae9004d – Jonathan Mee Feb 08 '18 at 15:33