3

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;
}
fedorqui
  • 275,237
  • 103
  • 548
  • 598
user1155299
  • 877
  • 5
  • 20
  • 29
  • "EST+15:00:00" This doesn't make sense. It should be "EST-05:00:00" – Karlson Jan 18 '12 at 21:32
  • it's converting to UTC. this is what it returns `osaka_time: 2012-Jan-03 11:00:00 UTC ` of course the date and time is wrong if we look at japan which is what I tried to use in this example – user1155299 Jan 18 '12 at 21:36
  • agreed, how do I get JST because that should be CST+15:00:00. if I do UTC + 9:00:00, it gives me the wrong date – user1155299 Jan 18 '12 at 22:00
  • jan. 3, 2012 instead of Jan.4, 2012. can you run the code I have posted – user1155299 Jan 18 '12 at 22:14
  • If you want to get 4pm Chicago in Osaka you should create `jpn_time` with `chi_tz` as the timezone and report Osaka time with `jpn_tz` as the target. Otherwise you would be getting `Jan 3, 2012 01:00:00` as the result. – Karlson Jan 18 '12 at 22:17
  • tried that, and did not work. can you post the code ;-) – user1155299 Jan 18 '12 at 22:21
  • You have not followed the example exactly. The Tz database isn't initialized so `America/Chicago` cannot be translated. – Karlson Jan 19 '12 at 02:12

2 Answers2

2

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;
}
Karlson
  • 2,958
  • 1
  • 21
  • 48
  • @Karison, changed it to single quotes but still same result. I think this is a good opportunity for me to learn boost, so I will try the struct and also check out the link. code help to a student like me is always helpful ;-) – user1155299 Jan 18 '12 at 20:52
  • @user1155299 Check the general example in the docs. But I still think that you most likely don't need it. Also check out [this question](http://stackoverflow.com/questions/2523286/mysql-convert-tz-help) – Karlson Jan 18 '12 at 20:56
  • in boost is it possible to convert directly from IST to CST, or do I need to convert IST to UTC and then UTC to CST – user1155299 Jan 18 '12 at 20:56
  • @user1155299 I've amended the answer. The last example does exactly that. From EST to MST – Karlson Jan 18 '12 at 21:00
  • @Karison, I just created sample code with the example you provided...any fix for the error – user1155299 Jan 18 '12 at 21:22
  • btw, I fixed it to -5:00:00 and it shows UTC time, not JST time, so it seems like one has to first convert to UTC and then to anything else – user1155299 Jan 18 '12 at 21:32
1

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

Pat Mustard
  • 1,852
  • 9
  • 31
  • 58