Конвертировать метки времени unix в день недели на C++?

Как я могу определить день недели в Калифорнии (Тихоокеанское время) на основе произвольной метки времени Unix (секунды)? Я искал вокруг, но не нашел встроенную библиотеку для C++.

UTC обычно на 8 часов опережает PT, но просто вычитает 8 часов из метки времени Unix и создает tm struct не работает, так как это скидки на летнее время нюансы.

3 ответов


вот как это сделать с помощью библиотека даты Говарда Хиннанта. Это бесплатная библиотека C++11/14 с лицензией MIT на основе <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() создает zoned_time<seconds> на основе unix_timestamp и time_zone "America / Los_Angeles". А zoned_time коллекция а time_zone и метка времени unix.

вы можете получить местное время из zoned_time С zt.get_local_time(). Это chrono::time_point но без часов, связанных с ним. Точность этой временной точки будет равна точности исходной отметки времени (в данном случае секунд).

вы можете получить день недели local_time путем отбрасывания local_time в точности days:

floor<days>(zt.get_local_time())

а в этот день-точность time_point преобразует в тип weekday.

A weekday можно распечатать, участвовать в weekday арифметика и сравнения, или быть явно преобразованы в unsigned в диапазоне [0, 6].

программы выше выдает:

Sun

часть часового пояса этой библиотеки является верным представлением база данных часового пояса IANA. Это даст правильные корректировки между местными часовыми поясами и UTC еще в середине 1800-х годов до сегодняшнего дня. Если вы передаете метки времени библиотеки до середины 1800-х годов самое раннее известное смещение UTC экстраполируется назад в год -32768. Вы также можете передать метки времени в будущем, как год 32767, и текущие правила смещения и летнего времени будут распространяться вперед.

поскольку эта библиотека построена на <chrono>, он будет обрабатывать любую точность, что <chrono> поставок. Обратите внимание, что некоторые chrono::durations, таких как nanoseconds имейте более ограниченный ряд (+/-292 лет для nanoseconds).

библиотека / процесс является потокобезопасным. То есть программа работает непосредственно с любым часовым поясом, который вы укажете, без изменения часового пояса вашего компьютера или переменных среды под капотом. Он также не включает часть API синхронизации C, которая, как известно, не является потокобезопасной из-за локальной статики функции non-const.

портирован на последние версии gcc, clang и VS.


хакерский способ с использованием стандартного UNIX C (не потокобезопасная версия):

#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 строка(s) для зона(ы) вам нужно. временной зоны формат является самым простым и рекомендуемым форматом для использования. Я использовал tzselect для генерации этого значения TZ для Тихоокеанского времени.

см. Также man 5 localtime, man tzselect для получения информации о стандартной настройке часового пояса UNIX.


можете ли вы использовать библиотеку Boost? Если вы можете выяснить строку часового пояса Posix (IEEE Std 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) для вашего часового пояса (PST), то пример ниже может помочь.

#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;
}