在 C++ 中将 unix 时间戳转换为星期几?
Convert unix timestamp (s) to day of week in C++?
如何根据任意 Unix 时间戳(秒)确定加利福尼亚州(太平洋时间)的星期几?我四处搜索,但没有找到 C++ 的内置库。
UTC 通常比 PT 早 8 小时,但是简单地从 Unix 时间戳中减去 8 小时并创建一个 tm
结构是行不通的,因为这会降低夏令时的细微差别。
你可以使用 Boost 库吗?
如果您能找出您所在时区 (PST) 的 Posix 时区字符串(IEEE 标准 1003.1,请参阅 http://www.boost.org/doc/libs/1_62_0/doc/html/date_time/local_time.html#date_time.local_time.posix_time_zone),那么下面的示例可能会有所帮助。
#include <iostream>
#include <ctime>
#include <boost/date_time.hpp>
int main(int argc, char ** argv)
{
std::string posix_time_zone_string = "EST-05:00:00"; // you need to change this to the posix time representation of your desired timezone
time_t unix_time = 1479641855; //1479641855 = Sun, 20 Nov 2016 11:37:35 GMT
boost::posix_time::ptime pt = boost::posix_time::from_time_t(unix_time);
std::cout << "time in UTC: " << boost::posix_time::to_iso_extended_string(pt) << std::endl;
boost::local_time::time_zone_ptr zone(new boost::local_time::posix_time_zone(posix_time_zone_string));
boost::local_time::local_date_time dt_with_zone(pt, zone);
std::cout << "time in local timezone: " << boost::posix_time::to_iso_extended_string(dt_with_zone.local_time()) << std::endl;
// Get the week day (alternative 1)
std::cout << "local week day integer: " << boost::local_time::to_tm(dt_with_zone).tm_wday << std::endl; // 0=sunday, 1=monday, etc.
// Get the week day (alternative 2)
std::cout << "local week day name: " << dt_with_zone.local_time().date().day_of_week() << std::endl;
std::cout << "local week day integer: " << int(dt_with_zone.local_time().date().day_of_week()) << std::endl;
return 0;
}
这是使用 Howard Hinnant's date library 的方法。这是一个免费的 MIT 许可的 C++11/14 库,基于 <chrono>
:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono_literals;
using namespace date;
auto unix_timestamp = sys_seconds{1479664467s};
auto zt = make_zoned("America/Los_Angeles", unix_timestamp);
auto wd = weekday{floor<days>(zt.get_local_time())};
std::cout << wd << '\n';
}
第一行只是构造 unix 时间戳(您可能从其他来源获得)。在 C++11 中,我们没有时间文字,因此这一行将改为:
auto unix_timestamp = sys_seconds{seconds{1479664467}};
make_zoned()
基于 unix_timestamp
和 time_zone
“America/Los_Angeles”创建 zoned_time<seconds>
。 zoned_time
是 time_zone
和 unix 时间戳的集合。
您可以使用 zt.get_local_time()
从 zoned_time
中获取本地时间。这是一个 chrono::time_point
但没有与之关联的时钟。该时间点的精度将等于您原始时间戳的精度(在本例中为秒)。
您可以通过将 local_time
截断为 days
的精度来获取 local_time
的本地星期几:
floor<days>(zt.get_local_time())
而这个日精度 time_point
将转换为类型 weekday
。
一个weekday
可以打印出来,参与weekday
运算和比较,或者显式转换为[0, 6].[=40范围内的unsigned
=]
以上程序输出:
Sun
该库的时区部分是 IANA timezone database 的忠实代表。它将在当地时区和 UTC 之间进行正确的调整,最早可以追溯到 1800 年代中期到现在。如果您在 1800 年代中期之前传递库时间戳,则已知最早的 UTC 偏移量将向后推断到 -32768 年。您还可以传递远至 32767 年的时间戳,当前偏移量和夏令时规则将向前传播。
由于此库是基于 <chrono>
构建的,因此它将处理 <chrono>
提供的任何精度。请注意,某些 chrono::duration
,例如 nanoseconds
的范围更有限(nanoseconds
为 +/-292 年)。
库/进程是线程安全的。也就是说,该程序直接与您指定的任何时区一起工作,而无需更改计算机的时区或环境变量。它也不涉及 C 时序的一部分 API,由于非常量函数局部静态,这部分已知不是线程安全的。
移植到最新版本的 gcc、clang 和 VS。
更新 C++20
上面的程序可以很容易地移植到 C++20(一些供应商在我写的时候支持这个,有些还不支持):
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
auto unix_timestamp = sys_seconds{1479664467s};
auto zt = zoned_time{"America/Los_Angeles", unix_timestamp};
auto wd = weekday{floor<days>(zt.get_local_time())};
std::cout << wd << '\n';
}
使用标准 UNIX C(非线程安全版本)的 Hacky 方式:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void print_times() {
char my_buf[100];
time_t now = time(NULL);
printf(ctime(&now));
strftime(my_buf, 100, "DoW=%w Tz=%Z\n", localtime(&now));
printf(my_buf);
}
int main( int argc, char * argv[] ) {
print_times();
setenv("TZ", "America/Los_Angeles", 1);
print_times();
unsetenv("TZ");
print_times();
}
不幸的是,TZ
env var 或更改文件 /etc/localtime
是影响 UNIX 时间函数时区设置的唯一方法(在后台 tzset() 使用这些来源来初始化一组共享变量,这些变量对所有库函数的时区设置进行编码。
问题是您需要使用 UNIX TZ string(s) for the zone(s) you need. zoneinfo 格式是最简单且推荐使用的格式。我使用 tzselect
生成太平洋时间的 TZ 值。
有关标准 UNIX 时区设置的信息,另请参阅 man 5 localtime
、man tzselect
。
如何根据任意 Unix 时间戳(秒)确定加利福尼亚州(太平洋时间)的星期几?我四处搜索,但没有找到 C++ 的内置库。
UTC 通常比 PT 早 8 小时,但是简单地从 Unix 时间戳中减去 8 小时并创建一个 tm
结构是行不通的,因为这会降低夏令时的细微差别。
你可以使用 Boost 库吗? 如果您能找出您所在时区 (PST) 的 Posix 时区字符串(IEEE 标准 1003.1,请参阅 http://www.boost.org/doc/libs/1_62_0/doc/html/date_time/local_time.html#date_time.local_time.posix_time_zone),那么下面的示例可能会有所帮助。
#include <iostream>
#include <ctime>
#include <boost/date_time.hpp>
int main(int argc, char ** argv)
{
std::string posix_time_zone_string = "EST-05:00:00"; // you need to change this to the posix time representation of your desired timezone
time_t unix_time = 1479641855; //1479641855 = Sun, 20 Nov 2016 11:37:35 GMT
boost::posix_time::ptime pt = boost::posix_time::from_time_t(unix_time);
std::cout << "time in UTC: " << boost::posix_time::to_iso_extended_string(pt) << std::endl;
boost::local_time::time_zone_ptr zone(new boost::local_time::posix_time_zone(posix_time_zone_string));
boost::local_time::local_date_time dt_with_zone(pt, zone);
std::cout << "time in local timezone: " << boost::posix_time::to_iso_extended_string(dt_with_zone.local_time()) << std::endl;
// Get the week day (alternative 1)
std::cout << "local week day integer: " << boost::local_time::to_tm(dt_with_zone).tm_wday << std::endl; // 0=sunday, 1=monday, etc.
// Get the week day (alternative 2)
std::cout << "local week day name: " << dt_with_zone.local_time().date().day_of_week() << std::endl;
std::cout << "local week day integer: " << int(dt_with_zone.local_time().date().day_of_week()) << std::endl;
return 0;
}
这是使用 Howard Hinnant's date library 的方法。这是一个免费的 MIT 许可的 C++11/14 库,基于 <chrono>
:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono_literals;
using namespace date;
auto unix_timestamp = sys_seconds{1479664467s};
auto zt = make_zoned("America/Los_Angeles", unix_timestamp);
auto wd = weekday{floor<days>(zt.get_local_time())};
std::cout << wd << '\n';
}
第一行只是构造 unix 时间戳(您可能从其他来源获得)。在 C++11 中,我们没有时间文字,因此这一行将改为:
auto unix_timestamp = sys_seconds{seconds{1479664467}};
make_zoned()
基于 unix_timestamp
和 time_zone
“America/Los_Angeles”创建 zoned_time<seconds>
。 zoned_time
是 time_zone
和 unix 时间戳的集合。
您可以使用 zt.get_local_time()
从 zoned_time
中获取本地时间。这是一个 chrono::time_point
但没有与之关联的时钟。该时间点的精度将等于您原始时间戳的精度(在本例中为秒)。
您可以通过将 local_time
截断为 days
的精度来获取 local_time
的本地星期几:
floor<days>(zt.get_local_time())
而这个日精度 time_point
将转换为类型 weekday
。
一个weekday
可以打印出来,参与weekday
运算和比较,或者显式转换为[0, 6].[=40范围内的unsigned
=]
以上程序输出:
Sun
该库的时区部分是 IANA timezone database 的忠实代表。它将在当地时区和 UTC 之间进行正确的调整,最早可以追溯到 1800 年代中期到现在。如果您在 1800 年代中期之前传递库时间戳,则已知最早的 UTC 偏移量将向后推断到 -32768 年。您还可以传递远至 32767 年的时间戳,当前偏移量和夏令时规则将向前传播。
由于此库是基于 <chrono>
构建的,因此它将处理 <chrono>
提供的任何精度。请注意,某些 chrono::duration
,例如 nanoseconds
的范围更有限(nanoseconds
为 +/-292 年)。
库/进程是线程安全的。也就是说,该程序直接与您指定的任何时区一起工作,而无需更改计算机的时区或环境变量。它也不涉及 C 时序的一部分 API,由于非常量函数局部静态,这部分已知不是线程安全的。
移植到最新版本的 gcc、clang 和 VS。
更新 C++20
上面的程序可以很容易地移植到 C++20(一些供应商在我写的时候支持这个,有些还不支持):
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
auto unix_timestamp = sys_seconds{1479664467s};
auto zt = zoned_time{"America/Los_Angeles", unix_timestamp};
auto wd = weekday{floor<days>(zt.get_local_time())};
std::cout << wd << '\n';
}
使用标准 UNIX C(非线程安全版本)的 Hacky 方式:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void print_times() {
char my_buf[100];
time_t now = time(NULL);
printf(ctime(&now));
strftime(my_buf, 100, "DoW=%w Tz=%Z\n", localtime(&now));
printf(my_buf);
}
int main( int argc, char * argv[] ) {
print_times();
setenv("TZ", "America/Los_Angeles", 1);
print_times();
unsetenv("TZ");
print_times();
}
不幸的是,TZ
env var 或更改文件 /etc/localtime
是影响 UNIX 时间函数时区设置的唯一方法(在后台 tzset() 使用这些来源来初始化一组共享变量,这些变量对所有库函数的时区设置进行编码。
问题是您需要使用 UNIX TZ string(s) for the zone(s) you need. zoneinfo 格式是最简单且推荐使用的格式。我使用 tzselect
生成太平洋时间的 TZ 值。
有关标准 UNIX 时区设置的信息,另请参阅 man 5 localtime
、man tzselect
。