7

I'm using the boost mysql library in a project. I need to use boost::mysql::datetime (datetime) to represent timestamps. A datetime value can be constructed from a boost::mysql::datetime::time_point.

using time_point = std::chrono::time_point< std::chrono::system_clock, std::chrono::duration< std::int64_t, std::micro >>;

How do I convert a "normal" std::chrono::system_clock::time_point to a boost::mysql::datetime::time_point?

As an interesting side note, boost::mysql does not use the boost Gregorian date library.

Details:

  • Ubuntu 24.04
  • C++23
  • Boost 1.88
  • gcc-14

Code:

#include <boost/asio.hpp>
#include <boost/mysql.hpp>
#include <chrono>
#include <exception>
#include <format>
#include <iostream>
#include <stdexcept>

int main()
{
    boost::mysql::datetime::time_point tp = std::chrono::system_clock::now();
    const std::time_t t_c = std::chrono::system_clock::to_time_t(tp);
    std::cout << "The system clock is currently at " << std::ctime(&t_c);
    
    return EXIT_SUCCESS;
}

The error for the above code:

main.cpp:11:75: error: conversion from ‘time_point<[...],duration<[...],ratio<[...],1000000000>>>’ to non-scalar type ‘time_point<[...],duration<[...],ratio<[...],1000000>>>’ requested
11 | boost::mysql::datetime::time_point tp = std::chrono::system_clock::now();

In case you want to reproduce my error message, here is the CMakeLists.txt file:

cmake_minimum_required(VERSION 3.31)

project(testTime LANGUAGES CXX)

if(POLICY CMP0167)
    cmake_policy(SET CMP0167 NEW)
endif()

find_package(Boost 1.87.0 REQUIRED COMPONENTS system charconv program_options)

add_executable(testTime main.cpp)

target_compile_options(testTime PRIVATE -Wall -Wextra -pedantic -Werror)

target_compile_features(testTime PRIVATE cxx_std_23)

target_link_libraries(testTime  ${Boost_LIBRARIES} ssl crypto)
4
  • 1
    Did you try std::chrono::time_point_cast? Commented Aug 31 at 14:46
  • @ChristianStieber I tried std::chrono::clock_cast, not time_point_cast. Commented Aug 31 at 14:48
  • 1
    Also note that mysql::datetime::now() does exactly this. You might find it useful. Should you need any more help, feel free to open a GitHub issue, since I tend to see these faster (I'm the author) Commented Sep 7 at 15:34
  • 1
    @anarthal Thank you for the heads up. I was using this as an example for a minimum reproducible case. My code stores std::chrono values in classes that are used throughout the application and then stores the classes in the database. Example, the last time a user would log into the system would be stored as a std::chrono::time_point (system clock). GitHub repository. You will find the Boost::MySql usage code in a side directory. Commented Sep 7 at 16:07

2 Answers 2

10

The chrono system does not allow implicit conversion from fine precision to coarser (though the reverse is allowed implicitly).

On your platform system_clock::now() returns nanoseconds precision and you desire microseconds precision.

There are 4 named conversion functions to do this, which differ only in rounding mode (how to truncate the extra nanoseconds):

  1. time_point_cast: truncates towards the epoch of 1970-01-01 00:00:00 UTC.
  2. floor: truncates to the previous microsecond.
  3. ceil : truncates to the next microsecond.
  4. round : truncates to the nearest microsecond.

Example:

namespace dt = std::chrono;
auto tp = dt::floor<dt::microseconds>(dt::system_clock::now());
std::cout << "The system clock is currently at " << tp << '\n';

Note: time_point_cast is equivalent to floor for times after the epoch, and equivalent to ceil for times prior to the epoch.

Note: If the source time happens to be on a microsecond boundary, then all 4 rounding modes give the same result (the microsecond the time_point is on).

Sign up to request clarification or add additional context in comments.

2 Comments

given there's a cmath function called ceil and floor, it would be easier to read/learn from your example if you used the complete namespace in the call like: std::chrono::floor<std::chrono::microseconds>(system_clock::now()); i know it's longer, but it removes all doubt.
Good comment. I'm allergic to excessive verbosity. I've struck a compromise with a namespace alias.
3

You need to use std::chrono::time_point_cast to convert to a time_point with a different duration:

boost::mysql::datetime::time_point boost = std::chrono::time_point_cast<boost::mysql::datetime::time_point::duration>(std::chrono::system_clock::now());

1 Comment

Good answer, and it works! I am going to accept the other answer because it is more complete.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.