HowardHinnant / date

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

zoned_time Operation is confusing, it's my wrong? Or lib wrong ? #757

Closed TomGarden closed 1 year ago

TomGarden commented 1 year ago

My Debian time zone setting : Asia/Shanghai

$ ls -al /etc/localtime
lrwxrwxrwx 1 root root 33  8月 15 22:24 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai

Test code :

/* Test code */
void ask() {
  const date::time_zone* timeZone = date::current_zone();
  std::chrono::system_clock::time_point timePoint =  std::chrono::system_clock::now();

  date::zoned_time zonedTime = date::make_zoned(timeZone, timePoint);
  std::chrono::time_point sysTP = zonedTime.get_sys_time();
  date::local_time<std::chrono::nanoseconds> localTP = zonedTime.get_local_time();
  uint64_t sysTimestemp = sysTP.time_since_epoch().count();
  uint64_t localeTimestemp = localTP.time_since_epoch().count();

  std::string dateFormatStr = "%Y-%m-%d %H:%M:%S";
  std::string sysStrFormat = date::format(dateFormatStr, sysTP);
  std::string localStrFormat = date::format(dateFormatStr, localTP);

  std::cout << "-------------------------------" << std::endl;
  std::cout << std::to_string(sysTimestemp)   << "\t"
            << sysStrFormat << "\t" << std::endl;
  std::cout << std::to_string(localeTimestemp) << "\t"
            << localStrFormat << "\t" << std::endl;
}
/* Test Code output content */
/* 
-------------------------------
1667271043906963213     2022-11-01 02:50:43.906963213
1667299843906963213     2022-11-01 10:50:43.906963213
 */

In fact if only the timestamp is calculated , the result is this :

My expected output is :

1667242243906963213     2022-11-01 02:50:43.906963213
1667271043906963213     2022-11-01 10:50:43.906963213
HowardHinnant commented 1 year ago

You question appears to boil down to the output of the values of the count of nanoseconds. The value of sysTimestemp is correct at 1667271043906963213. This is the number of nanoseconds that your call to system_clock::now() put into timePoint:

std::chrono::system_clock::time_point timePoint =  std::chrono::system_clock::now();  // 1667271043906963213ns

If you run this code again, and compare sysTimestemp == timePoint.time_since_epoch().count(), you will find that they hold equal values. As you put a sys_time into a zoned_time, the sys_time represents UTC, and that value remains constant as it is put into a zoned_time, and retrievied via .get_sys_time().

The human-readable format of 1667271043906963213ns is 2022-11-01 02:50:43.906963213 which is a UTC time stamp.

The local time in Shanghai at this UTC time point is 8h greater. When the zoned_time is asked to compute the local time for Shanghai, all it does is add 8h to the underlying UTC time stamp. This results in:

1667299843906963213 2022-11-01 10:50:43.906963213   
TomGarden commented 1 year ago

OK , now i understand myself wrong point .

I had a misunderstanding before : std::chrono::system_clock::now() will change with system time zone .

Now i know : std::chrono::system_clock::now() allways express UTC-0 time , the time zone of the operating system changes, does not affect the value of this api .

https://en.cppreference.com/w/cpp/chrono/system_clock say that :

The system_clock's time value can be internally adjusted at any time by the operating system, for example due to NTP synchronization or the user changing the system's clock. Daylight Savings Time and time zone changes, however, do not affect it since it is based on the UTC time-zone.

Thank you @HowardHinnant .