HowardHinnant / date

A date and time library based on the C++11/14/17 <chrono> header
Other
3.08k stars 669 forks source link

How to convert timezone for format date string ? #764

Open TomGarden opened 1 year ago

TomGarden commented 1 year ago
   I have one time string : `2022-12-13 10:32:06` . 
   I know  , the time string express the time of `Asia/Shanghai` timezone . 

   How to convert the time string to utc0 time date string : `2022-12-13 02:32:06` ?

   I know de-format date by `date::parse`
   I know format date by `date::format`

   how to convert timestamp(without timezone info) from one timezone to antoher timezone?
HowardHinnant commented 1 year ago
#include "date/tz.h"
#include <chrono>
#include <iostream>
#include <sstream>

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

    string input{"2022-12-13 10:32:06"};
    cout << input << '\n';
    istringstream in{std::move(input)};
    in.exceptions(ios::failbit);
    local_seconds ltp;
    in >> parse("%F %T", ltp);
    auto utp = locate_zone("Asia/Shanghai")->to_sys(ltp);
    string output = format("%F %T", utp);
    cout << output << '\n';
}

In a nutshell, the input is local_time. And one can use the time_zone "Asia/Shanghai" to transform it into sys_time (which is a close approximation to UTC). Then you can format the sys_time however you want.

This program outputs:

2022-12-13 10:32:06
2022-12-13 02:32:06

An alternative to:

    auto utp = locate_zone("Asia/Shanghai")->to_sys(ltp);

is:

    auto utp = zoned_time{"Asia/Shanghai", ltp}.get_sys_time();

They are both equivalent. zoned_time is just a pair of {time_zone*, time point}. The zoned_time constructor calls locate_zone and to_sys for you. In this example, one is about as good as the other. In other examples direct use of the time_zone is simpler, or the use of zoned_time is simpler. In the end, zoned_time is a simple wrapper around {time_zone*, time point} to enable some higher-level code to have simpler syntax.

A key point to observe in this example is that the input is parsed into a local_time type. This detail is what enables the type-safe transformation of the local time in "Asia/Shanghai" to sys_time.

In the event that the "other time zone" is not UTC, for example "America/New_York", then the use of zoned_time makes the syntax simpler:

    local_seconds ltp;
    in >> parse("%F %T", ltp);
    auto Stp = zoned_time{"Asia/Shanghai", ltp};
    auto Ntp = zoned_time{"America/New_York", Stp};
    string output = format("%F %T", Ntp);

Output:

2022-12-13 10:32:06
2022-12-12 21:32:06

One can construct one zoned_time from another and the invariant is that the two zoned_times will point to the same UTC time_point.

One could do this at the time_zone level, but the syntax would be slightly messier.

    local_seconds ltp;
    in >> parse("%F %T", ltp);
    auto utp = locate_zone("Asia/Shanghai")->to_sys(ltp);
    auto Ntp = locate_zone("America/New_York")->to_local(utp);
    string output = format("%F %T", Ntp);