I'm fighting a few days with COleDateTime in MFC.
I have CTime with correct values. Correct years, days, months, hours, minutes and seconds.
I tried a few ways to convert CTime to COleDateTime:
-1.I put CTime data to constructor of COleDateTime
COleDateTime(int nYear,int nMonth,int nDay, int nHour, int nMin,int nSec );
-2. I formatted CTime to time.Format("%m/%d/%y %H:%M:%S");
and passed to ParseDateTime of COleDateTime.
-3. Also I tried to use SetDateTime of COleDateTime
After that I'm getting incorrect values of minutes 1-2 min. more or less.
I have never seen it before and I couldn't find nothing in internet.Everybody says abot loss precision but this a second, not a minute.
Please advice something for me!
Thank you
I think the problem is that COleDateTime internally uses a float for storage, and the value represents the number of days since 30 December 1899.
As the number of days gets larger, the precision of the smaller fields (like minutes) decreases. For example, a float can accurately store the values 1000000 and 0.0000001, but it CAN'T store 1000000.0000001. It doesn't have enough bits of precision.
This limitation is hinted at in the MSDN documentation:
This type is also used to represent date-only or time-only values. By convention, the date 0 (30 December 1899) is used for time-only values. Similarly, the time 0:00 (midnight) is used for date-only values.
So basically, if you want a precise time, set the date to 30 December 1899.
It seems like Microsoft could have just designed this class to store the "days" portion as an integer, but hey, that would be too EASY.
Related
I'm trying to process timestep interval data. The data is of two formats:
1) each interval is explicitly set (e.g., 1982-12-31, 1988-01-01T00:00:00);
or
2) a start date is set followed by offsets of seconds, minutes, hours, days, months, or years
I've been using a combination of boost::gregorian::date and boost::posix_time::ptime to manage this, and use the facilities to get nicely formatted strings. However, I've now been presented with data that covers 1.9 million years, with each timestep being approximately 10 years. The start date is 0 and the last interval is 7e8. Obviously, I've hit the limits.
Is there a way using Boost to represent such scale? My searching has led to the conclusion 'no' in which case we'll just write our own class.
This is a very interesting question. But reaching the limits of boost in this area requires careful thinking about the risk of going beyond the astronomical limits of today.
Calendars and dates are very relative:
Posix time is defined as time elapsed from January 1st, 1970, not counting the leap seconds. boost allows you to choose between the microsecond or the nanosecond resolution at build time.
The gregorian calendar is defined since October 15th, 1582. Note that before 1930, some countries used the gregorian calendar and some still the julian one, the transition resulting in some interesting facts, such as the absence of 13 september 1752 in England and America.
Before it was the Julian calendar, defined by J.Caesar in 45 BC. Note that while the format, the number of month and length of month is the same than in the gregorian calendar, there are 13 days of difference between both, that take into account accumulated differences over the years.
before 45BC, was there the old roman calendar which had 355 days/year.
And longer before, until begin of mankind there were certainly all sorts of other calendars. But a days wasn't always 24 hours long. The variations of 1 to 3 microsecond per day of the solar day add up if you go in the millions of years. For instance, 600 millions of years ago, the averge length of the day was only 22 hours.
If you're working on both geological and narrow scales the easiest approach coud be to use a class or a union combining a long long (for geological scale in years BC) and boost::gregorian::date (for years AC, if you can afford the imprecision julian/gregorian). The nice formating would then be relatively easy to organize.
Alternatively you could consider use of chrono with the longest integer type and a ratio indicating that you'r counting the years:
typedef chrono::duration<long long, ratio<31556926, 1>> duration_in_year;
duration_in_year d2(1900000); // 1,9M years
chrono::time_point<chrono::system_clock> t1 = chrono::system_clock::now() - d2;
but nice printout will not be so evident as with boost. And you'll have to define your own clock class (The example above will work with 1,9Mio years but not much more, due to the parameters used to instantiate the system_clock class).
I am given the values for year, month,day,hour,minute and second in UTC. I need to calculate the milliseconds since the epoch (UTC).
How can this be achieved?
Thanks
If you can neglect leap seconds, this is quite easy with the right tools.
You will need:
days_from_civil located here.
A custom duration type representing days == 24 hours (shown below).
C++11's std::chrono or boost::chrono library (I'm showing it with std::chrono).
Here is how you create a custom chrono::duration that represents 24 hours:
typedef std::chrono::duration
<
std::int32_t, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
> days;
Now you are ready to write your function:
std::chrono::milliseconds
ms_since_UTC(int year, int month, int day, std::chrono::hours h,
std::chrono::minutes m, std::chrono::seconds s)
{
return days(days_from_civil(year, month, day)) + h + m + s;
}
days_from_civil will convert your year/month/day into the number of days since New Years 1970 (the UTC epoch). Your custom duration days will seamlessly interoperate with the "pre-defined" chrono durations: hours, minutes, seconds, and milliseconds. All of these durations will implicitly convert to milliseconds with no truncation error.
If you need to take leap seconds into account, then you will need to build a table of {days, chrono::seconds}, where the second part of the entry is the cumulative number of leap seconds you need to add to the duration if the current value of days is on or after the days entry in the table.
static constexpr std::pair<days, std::chrono::seconds> leap_seconds[25] =
{
std::make_pair(days(days_from_civil(1972, 7, 1)), std::chrono::seconds(1)),
// ...
};
Then you will need to search that table (using std::find_if, or std::lower_bound) to see if the return from days_from_civil lies prior to the table, within the table, or beyond the table. If prior to the table you add 0 leap seconds. If within the table, you add the appropriate number of leap seconds according to the table entry. If beyond the table you add (currently) 25 leap seconds.
return d + h + m + s + ls;
This is a "high maintenance" solution in that the table in this code will need to be updated every time they decide to add a leap second to UTC. It should also be noted that this solution can't be used with high confidence more than about 6 months in the future because one simply does not know if a leap second will be added (or subtracted) further in the future than that.
The days_from_civil code is in the public domain, so feel free to use it. It is efficient. And it has a +/- range of about 5.8 million years when given 32 bit signed inputs (so you don't really have to worry about breaching its range of validity). The paper goes into the gnarly details of how the algorithm works if you are interested.
As title, how to calculate time duration from epoch 1900 to now use boost?
Edit: Sorry about too short question at previous. I will describe my question again.
I have problem about save birthday to database as integer number. I have create four functions use as following:
ptime to integer (by day):
int ti=time_to_int(ptime(date(2012,1,1),0));
=> ti = 15430;//number of day from 1970 to 2012
integer to ptime:
ptime pt = int_to_time(15430);
ptime to string:
ptime pt(date(2012,1,1), 0);
string s = time_to_string(pt, "%d.%m.%Y");
string to ptime:
ptime pt = string_to_time(%d.%m.%Y);
PROBLEM:
Above, I have used epoch from 1970 and All work very well. So how can I convert 01/01/1945 to integer? I think that need use epoch from such as 1900.
However, when convert 01/01/2012 to int from 1900 it returns negative number, because "I think" tick count in miliseconds overflow (32bit).
Use some ways manual to calculate date to int is ok, but convert int back to date seems to bad. I want to use boost to do this.
Any suggestion?
Thanks!
Integer (int) is not big enough to hold the number of seconds since 1900. It can only hold about 68 years. You need to use a long (64 bit). Boost's time_duration will give you access to the number of seconds as a long. You could also use the number of days as mentioned by #jogojapan. However, day lengths are not always the same (23-25 hours), so sometimes keeping track of things in days is more prone to error (if you are careful it should be fine though).
Take a look at some examples from the documentation. You can subtract two ptime objects to get a time_duration:
time_duration td = ptime1 - ptime2;
long secElapsed = td.total_seconds();
I'm creating a mock object to test my application so that it works at the boundary conditions of time. I'm using FILETIME in the Windows SDK.
The link shows the earliest time which is January 1, 1601 (I'm assuming midnight 00:00:00 and both dwLowDateTime and dwHighDateTime are 0x00000000), so I have that. What is the latest possible FILETIME?
My first instinct is to set dwLowDateTime and dwHighDateTime to 0xFFFFFFFF, but then I questioned if that really is a valid time that I need to test, due to where my linked page says the SetFileTime function uses 0xFFFFFFFF to specify that a file's previous access time should be preserved.
My understanding is that FILETIME was made to represent any valid SYSTEMTIME in 64 bits. If you take the limit of SYSTEMTIME (last millisecond in 30827) then you end up with a FILETIME of 0x7fff35f4f06c58f0 by using SystemTimeToFileTime().
However, if you put 0x7fffffffffffffff into FileTimeToSystemTime() then you will end up in the year 30828, although this date is invalid for SYSTEMTIME. Any larger value (0x8000000000000000 and above) causes FileTimeToSystemTime() to fail.
All in all, I would recommend not to go beyond 0x7fff35f4f06c58f0 in order to stay compatible with SYSTEMTIME.
According to the link, FILETIME represents:
...the number of 100-nanosecond intervals since January 1, 1601 (UTC).
so not Jan 1st 1970.
It also says
...the SetFileTime function [for example] uses 0xFFFFFFFF to specify that a file's previous access time should be preserved.
So I don't think you would expect 0xFFFFFFFF to be a valid max value.
According to patent 6853957, the range is 30,000 years before/after the epoch (Jan 1, 1601). That implies you can use it with negative dates (i.e. dates before the epoch) too.
EDIT: Just calculated: it can store (approx) 58,454 days worth of 100-nanosecond intervals, so +/- 30,000 years sounds like a good value to go with, if you accept negative dates of course.
There is an answer in this MSDN article - Test Cases for the RTC Real-Time Functions Test:
The test looks for the range beginning with the minimum possible FILETIME (FILETIME 0 is the start of Jan 1st 1601) and end with maximum possible FILETIME (Max FILETIME is the maximum 64-bit value).
UPDATE: The "fraction of a second" parameter to Timestamp's constructor actually takes nanoseconds... I guessed it was hundredths of a second and my low values were rounded away. Question left for reference....
I'm struggling with Oracle's C++ library - OCCI. Summarily:
creating Timestamp objects and verifying they're good to hundredths of a second (though I'd like more!)
using stmt.setTimestamp then executeUpdate() to insert into a TIMESTAMP(6) column which should preserve microseconds
selecting the row in Oracle SQL Developer: the sub-second component is always 0-ed e.g. 14-JUL-11 06.03.27.000000000.
Problem
I need subsecond precision - hopefully microseconds! We've put a lot of work into capturing that precision in our servers and need (at least some of) it for analysis.
Details
I create a Timestamp from year/month/day hour/minute/second/millisecond, reducing the last to hundredths of a second as that seems to be what the constructor supports. (No Oracle documentation I can find specifies the interpretation, but in a fromText example "xff" clearly corresponds to a ".##" hundredths suffix in the value to convert. What's the point of TIMESTAMP(6) supporting 6 decimal places if you can't insert them?)
oracle::occi::Timestamp temp =
oracle::occi::Timestamp(_env, year, month, day,
hour, minute, second, millisecond / 10);
// re-extract the broken-down time from temp to prove it's stored successfully
int ye;
unsigned mo, da, ho, mi, se, fs;
temp.getDate(ye, mo, da);
temp.getTime(ho, mi, se, fs);
return temp;
Here, fs gets the milliseconds/10 value as expected.
I use this as in:
oracle::occi::Timestamp ts;
ts = _pImpl->makeOracleTimestamp(p->ATETimeStamp);
stmt.setTimestamp(11, ts);
Where field 11 is a TIMESTAMP(6).
Selecting the row in Oracle SQL Developer, the other parts of the timestamp column are correct but the sub-second component is 0-ed ala 14-JUL-11 06.03.27.000000000.
Any insight much appreciated!
(If relevant, using MSVC++ 2005, Oracle 10.2.0.4 sdk, SQL Developer 3.0.04 - please ask if something else might be relevant).
Thanks,
Tony
Turns out the "fractional seconds" field is nominally in nanoseconds rather than hundredths. I wish Oracle would say that in their documents! I say nominally because if it really preserved the least-significant digits then the hundredths values I had would have appeared as a number of nanoseconds and I might have immediately guessed at the problem - instead it seems values < 100 nanoseconds are lost anyway (and perhaps bigger - I haven't probed the cut-off point).
Thanks to anyone who had a look at the question or tried some research / investigation.