converting datetime to different timezone in C++/boost

放肆的年华 提交于 2019-12-10 21:36:27

问题


I have price data for the Indian stock market, but the time and date stamp on it is GMT, so I can work with the data representing the correct date and time.

I need to convert the date and time for some of the records in my DB into IST from GMT, my current time zone.

mysql> desc price_hist;
+---------------+-----------------------+------+-----+---------+----------------+
| Field         | Type                  | Null | Key | Default | Extra          |
+---------------+-----------------------+------+-----+---------+----------------+
| trade_id      | int(11)               | NO   | PRI | NULL    | auto_increment |
| contract_name | varchar(14)           | NO   | MUL | NULL    |                |
| trade_date    | date                  | NO   |     | NULL    |                |
| trade_time    | varchar(6)            | NO   |     | NULL    |                |
| trade_price   | decimal(10,4)         | NO   |     | NULL    |                |
| trade_volume  | bigint(20)            | NO   |     | NULL    |                |
+---------------+-----------------------+------+-----+---------+----------------+
8 rows in set (0.02 sec)

I tried to change the timezone in the DB itself by running, but that did not work:

select convert_tz("2010-06-30 19:00:00",'GMT','IST');
+-----------------------------------------------+
| convert_tz("2011-06-30 09:00:00",'GMT','IST') |
+-----------------------------------------------+
| NULL |
+-----------------------------------------------+
1 row in set (0.01 sec) 

I am new to Boost, but I have been suggested to use Boost date to handle this in the code itself.

I searched some of the posts for datetime conversion but did not find a post that would answer my specific question.

If there is a specific link or better still, example boost code someone could share, that would be a great start for a nubee like me. :-)

I used the reference @Karison provided to write the following code:

#include "boost/date_time/local_time/local_time.hpp"
  #include <iostream>

  int  main() 
  {
    using namespace boost::posix_time;
    using namespace boost::gregorian;
    using namespace boost::local_time;

    tz_database tz_db;
    time_zone_ptr chi_tz=tz_db.time_zone_from_region("America/Chicago");
    time_zone_ptr jst_tz(new posix_time_zone("EST+5:00:00"));


    local_date_time jpn_time(date(2012,Jan,3), hours(16), jst_tz,local_date_time::NOT_DATE_TIME_ON_ERROR);
    local_date_time osaka_time = jpn_time.local_time_in(chi_tz);
    std::cout<<"osaka_time: "<<osaka_time<<std::endl;
return 0;
}

回答1:


First off let's change the syntax and separate the questions as I can see there are 3.

First syntax of convert_tz takes a string which the call should look like:

select convert_tz('2011-06-30 09:00:00','GMT','IST')

Single ticks not double quotes.

Second. If your machine is located in the same timezone and you are running on POSIX compliant system you can get the string representing the date and do:

struct tm result;
strptime(<time string>, <format string>, &result);
time_t epoch_time = mktime(&result);

which will give you the standard UNIX time which you can then use to do whatever you need.

Last but not least Boost. It's a powerful library to be sure but I don't think that for the project you will need to add complexity of it at this time. If you still feel like trying it out or you are not on POSIX compliant system you can take a look at http://www.boost.org/doc/libs/1_48_0/doc/html/date_time.html, which you will still need to create ptime from the string you are returning from the database and then manipulate it as you see fit. Using local_time portion create the timezone objects as you need and then check time you get from the database against it. You can look at the examples in http://www.boost.org/doc/libs/1_48_0/doc/html/date_time/examples/general_usage_examples.html

Especially the last one. So for your example it will be:

time_zone_ptr src_zone(new posix_time_zone("IST+05:30:00"));
time_zone_ptr dst_zone(new posix_time_zone("CST"));
local_date_time trd_time(date(....), hours(...), src_zone, 
                         local_date_time::NOT_DATE_TIME_ON_ERROR);
local_date_time res_time = trd_time.local_time_in(dst_zone);

Can't guarantee that it will be 100% correct but you get the idea.

Example:

#include "boost/date_time/local_time/local_time.hpp"
#include <iostream>

int  main() 
{
    using namespace boost::posix_time;
    using namespace boost::gregorian;
    using namespace boost::local_time;

    tz_database tz_db;
    time_zone_ptr chi_tz(new posix_time_zone("CST-06:00:00");
    time_zone_ptr jst_tz(new posix_time_zone("JST+09:00:00"));

    local_date_time jpn_time(date(2012,Jan,3), hours(16),
                             chi_tz,local_date_time::NOT_DATE_TIME_ON_ERROR);
    local_date_time osaka_time = jpn_time.local_time_in(jst_tz);
    std::cout<<"osaka_time: "<<osaka_time<<std::endl;
    return 0;
}



回答2:


Here are a couple of ways of addressing this:

1) Windows:

#include "stdafx.h"
#include <windows.h>

#include <iostream>
#include <string>
#include <locale>
#include <time.h>
#include <vector>

#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

using namespace boost::posix_time;
using namespace boost::gregorian;
using namespace boost::local_time;

//***********
// U T I L S
//***********

std::string WCHAR2StdString(WCHAR* wchar_buf)
{
    char narrow_buf[260];
    char DefChar = ' ';
    WideCharToMultiByte(CP_ACP,0,wchar_buf,-1, narrow_buf,260,&DefChar, NULL);
    return std::string (narrow_buf);
}

std::string LocalTimeZone(TIME_ZONE_INFORMATION & tzi)
{
    short int tz_bias = tzi.Bias;
    std::string tzName(WCHAR2StdString(tzi.StandardName));

    // Get acronym for X_(Zone) Standard Time: 'X_ST'
    std::vector<std::string> vec;
    boost::split(vec, tzName, boost::is_any_of(" "));
    std::string result;
    for(std::vector<std::string>::iterator i = vec.begin(); i != vec.end(); ++i)
    {
        std::string s = *i;
        char c = s.c_str()[0];
        result += c;
    }
    return result;
}

//**********
// M A I N
//**********

int _tmain(int argc, _TCHAR* argv[])  
{
    using namespace boost::posix_time;
    using namespace boost::gregorian;
    using namespace boost::local_time;

    // Windows Timezone info.
    TIME_ZONE_INFORMATION tzi;
    DWORD res = GetTimeZoneInformation(&tzi);

    // Timezone string
    std::string local_tz_str = LocalTimeZone(tzi);

    // Hour Bias
    std::stringstream ss;
    ss << (abs(tzi.Bias)/60);
    std::string bias_hrs(ss.str());

    // Build string: e.g. CST+08:00:00
    short int sign = 0;
    tzi.Bias > 0 ? sign = -1 : sign = 1;

    // Pad with zeros as necessray
    if(abs(tzi.Bias/60) < 10) bias_hrs = ("0" + bias_hrs);
    bias_hrs += ":00:00";
    (sign > 0) ? (bias_hrs = local_tz_str + "+" + bias_hrs) : (bias_hrs = local_tz_str + "-" + bias_hrs);

    local_tz_str = bias_hrs; // local_tz_str is a better name to continue with

    std::string formatted_tz_desc(bias_hrs);

    // Construct local_date_time and time_zone etc.
    long long ticksFromEpoch = 1329122250168; // !!! (assumed input format) milliseconds from 1970-01-01 00:00:00
    std::time_t tt = static_cast<time_t>(ticksFromEpoch/1000); // (ticksFromEpoch/1000) gives seconds since epoch 
    ptime pt = from_time_t(tt);
    time_zone_ptr zone(new boost::local_time::posix_time_zone(formatted_tz_desc));
    local_date_time locally_adjusted_date_time(pt, zone);

    // Format stringstream: YYYY-Mmm-dd HH:MM:SS
    std::stringstream strm;
    strm.imbue(std::locale(std::cout.getloc(), new local_time_facet("%Y-%m-%d %H:%M:%S")));
    strm << locally_adjusted_date_time;

    // Print adjusted result
    std::cout << strm.str() << std::endl << std::endl; 

    return 0;
  }

You can get time zone info from the std c libs like this:

2) Posix:

#include <stdio.h>
#include <time.h>
#include <string>
#include <iostream>
#include <vector>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

std::string LocalTimeZone();

int main() {
    std::cout << LocalTimeZone() << std::endl;
    return 0;
}

std::string LocalTimeZone()
{
    time_t  now = time(NULL);
    struct tm tnow = *localtime(&now);
    std::string tz = tnow.tm_zone;

    // Format the struct:
    char    buff[100];
    strftime( buff, sizeof buff, "%a %b %d %Y %T %Z%z", &tnow );

    // Parse the bits you want:
    std::vector<std::string> vec;
    const std::string s(buff);
    boost::split(vec, s, boost::is_any_of(" "));
    std::vector<std::string>::iterator i = vec.end();

    return *--i;
}

Once you format the time zone string e.g. CST+08:00:00 you can proceed with the boost method shown above.

HTH



来源:https://stackoverflow.com/questions/8916071/converting-datetime-to-different-timezone-in-c-boost

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!