compare function for dates - c

I have struct as:
struct stored
{
char *dates; // 12/May/2010, 10/Jun/2010 etc..
};
// const
struct stored structs[] = {{"12/May/2010"}, {"12/May/2011"},
{"21/May/2009"}, {"13/May/2011"},
{"10/May/2011"}, {"19/May/2011"}};
What I want to do is to sort struct 'stored' by stored.dates.
qsort(structs, 9, sizeof(struct stored*), sortdates); // sortdates function
I'm not quite sure what would be a good way to sort those days? Compare them as c-strings?

I would convert the dates to numbers using something like:
year * 10000 + month * 100 + day;
and then do a simple numeric comparison (and for month, you'll need to map from Jan to 1, Feb to 2, etc.).
If you're doing a lot of comparisons, you may want to cache the numeric equivalent in the structure.

If you convert the dates to the format YYYYMMDD (as in 20100314), you can compare them as a string or as an integer (after conversion).

ISO 8601 formatted dates ("YYYYMMDD" or "YYYY-MM-DD" etc.) are trivially comparable as C strings. Your format is not - would changing the format of the date strings be an option?
PS: If you get rid of the "-", you could even store the date as plain 32bit integer. Depending on what your application does with those dates, that might be an additional bonus.

You can't compare these as strings, but you can compare substrings. Compare the years, and if they aren't equal you have your answer. Next compare the months, you'll need some kind of table to order the months by name. Finally if the months are the same, compare the days.

Related

Postgres Date Type Value

Want to retrieve a date type from a postgres table using liqpq PQexecParams() in binary mode (please humor me).
https://www.postgresql.org/docs/14/datatype-datetime.html says that a date is 4 bytes (4713 BC to 5874897 AD).
src/include/utils/date.h defines:
typedef int32 DateADT;
But obviously given the supported date range it's not a normal int. Something like this:
int32_t haha = be32toh(*((uint32_t *) PQgetvalue(res, 0, 17)));
Gives haha=1466004328 for 2022-10-25.
Which is clearly not a day count and since its not a ratio of 86,400 is also not seconds since an epoch. Number is also too small to be microseconds.
How do I interpret the 4 bytes of postgresql 'date' data?
Added Later:
This question contains an error - PQgetvalue() references column 17 (a text value) instead of column 18 (a date value) - with that corrected haha=8332
Date is an integer day count from POSTGRES_EPOCH_JDATE (2000-01-01).

How to pull specific indices out of a character array in a loop?

I have an array that contains multiple dates in the format yyyymmdd, stored as a 50x1 double. I am trying to pull out the year,month, and day so I can use datenum to assign each date a serial number.
Indexing an individual date, converting the using str2num, then indexing and pulling the appropriate values works fine, but when I try to loop through the list of dates it doesn't work- only variations of the number 2 are returned.
dates = [20180910; 20180920; 20181012; 20181027; 20181103; 20181130; 20181225];
% version1
datesnums=num2str(dates); % dates is a list of dates stored as
integers
for i=1:length(datesnums)
pullyy=str2num(datesnums(1:4));
pullmm=str2num(datesnums(5:6));
pulldd=str2num(datesnums(7:8));
end
As well as
%version2
datesnums=num2str(dates,'%d')
for i = 1:length(datesnums)
dd=datenum(str2num(datesnums(i(1:4))),str2num(datesnums(i(5:6))),
str2num(datesnums(i(7:8))));
end
I'm trying to generate a new array that is just the serial numbers of the input dates. In the examples shown, I am only getting single integer values, which I know is because the loop is incorrect and I get errors that say "Index exceeds the number of array elements (1)." for version 1. When I've gotten it to successfully loop through everything, the outputs are just '2222','22,'22' for every single date which is incorrect. What am I doing wrong? Do I need to incorporate a cell array?
To get all the years, month, and days in a loop:
datesnums=num2str(dates);
for i=1:size(datesnums, 1)
pullyy(i) = str2num(datesnums(i,1:4));
pullmm(i) = str2num(datesnums(i,5:6));
pulldd(i) = str2num(datesnums(i,7:8));
end
Actually, you can do this without a loop:
pullyy = str2num(datesnums(:,1:4));
pullmm = str2num(datesnums(:,5:6));
pulldd = str2num(datesnums(:,7:8));
Explanation:
If for example the dates vector is a [6x1] array:
dates =[...
20190901
20170124
20191215
20130609
20141104
20190328];
Than datesnums=num2str(dates); creates a char matrix of size [6x8] where each row corresponds to one element in dates:
datesnums =
6×8 char array
'20190901'
'20170124'
'20191215'
'20160609'
'20191104'
'20190328'
So in the loop you need to refer to the row index for each date and and the column indices to extract the years, month, and days.
The easiest solution I can think of is:
SN = datenum(num2str(dates),'yyyymmdd')
You only have to specify the date format which is 'yyyymmdd'

count number of weekdays between two date strings in C99

I have two date strings in the form yyyy-mm-dd , just like
const char* date_start = "2015-09-30";
const char* date_end = "2015-10-03";
How do I calculate the number of weekdays (number of days which are neither Saturday nor Sunday) between the two dates? Dates where start and end day are equal can exists (the day count should be equal to 1 (workday) or 0 (weekend) then). All input dates are guaranteed to be valid (e.g. no 30th of February).
The solution need to work with C99 on OS X as well as Windows and independent of the system locale settings.
I would prefer to use as little external code (i.e. libraries or frameworks) as possible.
Pseudo Code
Form time structures
struct tm start = {0};
start.tm_year = 2105-1900;
start.tm_mon = 9-1;
start.tm_mday = 30;
start.tm_isdst = 0;
struct tm end = ...
Form time number and set tm_wday field
time_t tstart = mktime(&start);
time_t tend = mktime(&end);
Find day difference
double day_diff = difftime(&tend, &tstart)/(24.0*60*60);
Some magic per weekday (left for OP)
numweekdays = ((long)day_diff/7)*5 + foo(start->tm_wday, end->tm_wday);
convert date-strings to something more handable, like "long date since 1.1.1970", if that suits your use case; or "struct tm"
calculate the difference in days (end minus start plus one)
for each complete week inside the difference (> 7) add 5 weekdays/2 weekends
calculate the weekday-status for the rest (at least 6) days and add them accordinly

Different results from STRREAD() for reading strings

I have a date cell array which is read from a csv file. The format is below:
date =
'2008.12.01'
'2008.12.02'
'2008.12.03'
'2008.12.04'
'2008.12.05'
... ...
And I want to:
turn the cell array to a string array,
use the strread() to read its "yyyy","mm" and "dd" value into 3 double array [year,mm,dd],
use the datenummx() to turn [year,mm,dd] into date seriel num.
After i use
date = char(date);
the date array become like this:
date =
2008.12.01
2008.12.02
2008.12.03
2008.12.04
2008.12.05
... ...
which I think the result is what i want...
But after I use the strread(), it gives me odd result.
[year,month,day]=strread(date,'%d%d%d','delimiter','.');
year =
-1
0
0
0
0
... ...
BUT if I use the code below, the strread() can give me the right answer:
s = sprintf('2008.12.01')
s =
2008.12.01
[year,month,day]=strread(s,'%d%d%d','delimiter','.')
year =
2008
month =
12
day =
1
And I checked in the matlab that both the "date" and "s" is a char array.(by using function 'ischar' and simply display both)...
But why do the strread() give differnt results?
Can anyone answer?
by the way, I use the MatLab v6.5.(for my own reason, so please don't comment by asking "why not use a higher version")....
Your problem is this line:
date = char(date);
It does not create an array of strings, there is no array of strings in matlab. It creates an array of chars. As you already noticed, your strread-line is fine if you input a single date, so input each date form your original cell array individually:
for idx=1:numel(date)
[year(idx),month(idx),day(idx)]=strread(date{idx},'%d%d%d','delimiter','.');
end
Preallocation of year, month and day improves the performance.

Matlab: Number of observations per year for very large array

I have a large array with daily data from 1926 to 2012. I want to find out how many observations are in each year (it varies from year-to-year). I have a column vector which has the dates in the form of:
19290101
19290102
.
.
.
One year here is going to be July through June of the next year.
So 19630701 to 19640630
I would like to use this vector to find the number of days in each year. I need the number of observations to use as inputs into a regression.
I can't tell whether the dates are stored numerically or as a string of characters; I'll assume they're numbers. What I suggest doing is to convert each value to the year and then using hist to count the number of dates in each year. So try something like this:
year = floor(date/10000);
obs_per_year = hist(year,1926:2012);
This will give you a vector holding the number of observations in each year, starting from 1926.
Series of years starting July 1st:
bin = datenum(1926:2012,7,1);
Bin your vector of dates within each year with bin(1) <= x < bin(2), bin(2) <= x < bin(3), ...
count = histc(dates,bin);

Resources