C Get Date Sometimes Wrong By 1 Day - c

So finally after a lot of time googling I've been able to create a function that gets current date and convert it to string then write to buffer in C. But I noticed sometimes the day is off by 1? So for example today is may 4, but it may return may 5
Here is my code
void getCurrentDateTime(char * buffer)
{
time_t t = time(NULL);
struct tm *tm = localtime(&t);
char bufForOut[64] = { 0 };
strftime(bufForOut, sizeof(bufForOut), "%c", tm);
strcpy(buffer,bufForOut);
}
I call it like
char hi[64] = { 0 }
getCurrentDateTime(hi);
print(hi);

Related

time.h - struct tm and milliseconds

I have log data ranging from 1000 to 100000 entries all from different sources. The objective is to sort this data by time (quickly). I was prototyping in C and i'm stuck because it looks like tm doesn't support milliseconds. Am i missing something here ? Any suggestions ?
Idea:
Open file. Parse line-by-line and tokenize fields to c struct via strtok
1.1 Convert Date & Time to "struct tm".
1.2 Build linked list
Sort linked list based on time (don't know which sort algorithm i'd use)
Output
[Example]
YYYY-MM-DD,HH:MM:SS:MS , PID, TID , COMPONENT, Message
2017-03-29,20:56:27:088, 3436,2568,COMPONENT, Message String blah blah
2017-03-29,20:56:27:089, 3436,2568,COMPONENT, Message String baaaaa
2017-03-29,20:56:27:079, 3436,2568,COMPONENT, Message String roarrr
2017-03-29,20:56:28:061, 3436,2568,COMPONENT, Message String meow
2017-03-29,20:56:25:044, 3436,2568,COMPONENT, Message String ruff ruff
.
.
.
100000 entries
const char T[] = "2017-03-29,20:56:27:088"; //Test String
time_t result = 0;
int year = 0, month = 0, day = 0;
int hour = 0, min = 0, sec = 0, ms = 0;
if (sscanf(T, "%4d-%2d-%2d,%2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec) == 6) {
struct tm tv = {0};
tv.tm_year = year;
tv.tm_mon = month;
tv.tm_mday = day;
tv.tm_hour = hour;
tv.tm_min = min;
tv.tm_sec = sec;
//Crap, it doesn't look like tm handles milliseconds ????
if ((result = mktime(&tv)) == (time_t)-1) {
fprintf(stderr, "Conversion Error\n");
}
puts(ctime(&result));
}
else {
fprintf(stderr, "Invalid Format\n");
}
I don't understand why you need to convert those timestamps into a struct tm, or into any other representation. They will already lexicographically sort just the way you want, in their current string form. So just do that.
You can take the result you get back from mktime and convert it to milliseconds.
if ((result = mktime(&tv)) == (time_t)-1) {
fprintf(stderr, "Conversion Error\n");
}
long long resultmilli = (result * 1000LL) + ms;

C MongoDB driver DateTime update

Ok this is the scenario. I am reading txt file and inserting/updating (with bulk operations ) data to mongodb.
Inserting part works fine since I am creating bson document in a loop and doing mongoc_bulk_operation_insert.
My date comes in a format of 11:37:17.253 SAST JUN 05 2015
so I run it trough the function that removes .253 and SAST
and feed it to the convert_to_date function that you see down in the text.
This is how I create timestamp and append the date to the document:
int convert_to_date(char *dateString)
{
struct tm *parsedTime;
time_t rawTime;
time_t newTime;
int hour, minutes, seconds, millis, year, month, day;
if (sscanf(dateString, "%d:%d:%d %d %d %d",
&hour, &minutes, &seconds, &month, &day, &year) != EOF) {
time(&rawTime);
parsedTime = localtime(&rawTime);
parsedTime->tm_year = year - 1900;
parsedTime->tm_mon = month - 1;
parsedTime->tm_mday = day;
parsedTime->tm_hour = hour;
parsedTime->tm_min = minutes;
parsedTime->tm_sec = seconds;
newTime = mktime(parsedTime);
return newTime;
}
return 0;
}
/* this is somewhere in a loop */
time_t t = convert_to_date(s1);
bson_append_time_t(doc, field_map[y], strlen(field_map[y]), t);
// and after all if insert is supposed to happen i call
// mongoc_bulk_operation_insert(bulk, doc);
// and mongoc_bulk_operation_execute(bulk, &reply, &error);
That part is just fine when I look at the database I get
ISODate("2015-06-05T09:37:17.000Z")
So ther problem is when I try to update existing record.
When i do update i need to do a $set on all of the fields I want to update(upsert actually and I didnt find a way to update complete document at once)
it looks like this:
//update document with sessionid
query = BCON_NEW("SessionId", BCON_UTF8(sid));
update = BCON_NEW("$set", "{", "SomeDateTimeField",
BCON_DATE_TIME(ystack[y]), "}");
mongoc_bulk_operation_update(bulk, query, update, true);
The value of ystack[y] is 1433497048 which is valid timestamp but
i get in the db ISODate("1970-01-17T14:11:37.037Z")
I also found an example online for inserting the whole bson object as date like this:
int64_t currentTime = time(NULL) * 1000;
bson_t *date = BCON_NEW("$date", BCON_DATE_TIME(currentTime));
bson_t *update = BCON_NEW("$set", "{", "last_sync_time", date, "}");
But this produces \u0001 in the DB instead of valid date. I cant tell what is causing this, so much frustration for something that should be straight forward. This is the libbson api for the reference
https://api.mongodb.org/libbson/current/index.html
and c driver api
http://api.mongodb.org/c/1.1.8/
Ok I found the solution myself, should have read the api more carefully :)
The BCON_DATE_TIME accepts milliseconds instead of seconds which I passed to it.
I actually tried to multiply by 1000 before but since my var was int it could not store the correct value.
I had to declare it as
unsigned long long
Here is the changed code just for reference
long convert_to_long(char *dateString)
{
struct tm *parsedTime;
time_t rawTime;
time_t newTime;
int hour, minutes, seconds, millis, year, month, day;
if (sscanf(dateString, "%d:%d:%d %d %d %d",
&hour, &minutes, &seconds, &month, &day, &year) != EOF) {
time(&rawTime);
parsedTime = localtime(&rawTime);
parsedTime->tm_year = year - 1900;
parsedTime->tm_mon = month - 1;
parsedTime->tm_mday = day;
parsedTime->tm_hour = hour;
parsedTime->tm_min = minutes;
parsedTime->tm_sec = seconds;
newTime = mktime(parsedTime);
unsigned long long millis = newTime * 1000;
return millis;
}
return 0;
}

Time convert from a file and compare to the current time

I've asked something close to this before, but as it seems, the time I get from the file does not convert to the same type of time you get from localtime() and time().
Exactly what I want is:
I have a txt file with the following information
order.txt
file1.txt;5;15:40
file2.txt;7;15:41
file1.txt;10;16:00
My objective is to get the time in hour:min (15:40) and then, if it's the same as the currentTime, then I show the file1.txt content. Otherwise, if the currentTime is lower than the hour:min time (15:40), it waits untill it's 15:40 and shows the file1.txt content. If the currentTime is higher, then it ignores the first one and goes to the next one.
So for example, if the current time is 15:39, it will wait 1 minute and then show the file1.txt content.
If the current Time is 15:40, it shows the file1.txt content without waiting.
If the current Time is 15:41, it just goes to the next one (file2.txt) and checks again.
Used variables
FILE* orderFile;
FILE* contentFile;
FILE* defaultFile; (This will be used when this code works)
char fileName[50];
char textContent[5000];
int seconds;
int hour, min;
int diff_time;
char timeValue[50];
time_t current;
Includes
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
So for that I've tried the following code:
orderFile = fopen("order.txt","r");
defaultFile = fopen("default.txt","r");
while(fscanf(orderFile," %49[^;];%d; %49[^\n]",fileName,&seconds,timeValue)
{
sscanf(timeValue,"%d:%d",&hour,&min);
contentFile = fopen(fileName,"r");
if(contentFile != NULL)
{
fseek (contentFile, 0, SEEK_END);
size = ftell(contentFile);
rewind(contentFile);
if(size == 0)
{
printf("\nEmpty file. (Scanned file: %s)\n", fileName);
fclose(contentFile);
}
else
{
time_t now;
time(&now);
struct tm file_time_tm;
file_time_tm = *localtime(&now);
file_time_tm.tm_hour = hour;
file_time_tm.tm_min = min;
file_time_tm.tm_sec = 0;
file_time_tm.tm_isdst = -1;
time_t fileTime = mktime(&file_time_tm);
double diff_time = difftime(fileTime, now);
if(diff_time == 0)
{
while(fscanf(contentFile,"%[^\t]",textContent) == 1)
{
printf("%s\n", textContent);
}
sleep(seconds);
}
else
{
if(diff_time > 0)
{
while(fscanf(defaultFile,"%[^\t]",defaultContent) == 1)
{
printf("%s\n", defaultContent);
}
sleep(diff_time);
while(fscanf(contentFile,"%[^\t]",textContent) == 1)
{
printf("%s\n", textContent);
}
sleep(seconds);
}
}
fclose(defaultFile);
fclose(contentFile);
}
}
else
{
if(contentFile == NULL)
{
printf("\nFile does not exist. (Scanned file: %s)\n", fileName);
fclose(contentFile);
}
}
}
fclose(orderFile);
printf("\n");
So thanks to chux it is quite working now, yet not fully working.
If I have the following:
Current Time: 15:00
order.txt
file1.txt;5;15:01
file2.txt;6;15:02
file3.txt;3;15:03
When I run the program, the following will occur:
DEFAULT MESSAGE (text inside default.txt)
WAITS DIFF_TIME (CORRECTLY DONE)
SHOWS CONTENT FROM THE file1.txt
WAITS 5 SECONDS
X - SHOWS CONTENT FROM THE file2.txt (This is wrong, it should check again and if the time is 15:02 it will show, not 15:01. Which I assume it's because it is still reading as 15:01 on the timeValue and not 15:02, any idea why?)
WAITS UNTILL IT'S 15:02 (wrong)
SHOWS file3.txt (wrong)
WAITS UNTILL IT'S 15:03
ENDS (wrong as it should not end after waiting, it should end when file3.txt shows and waits for 3 seconds)
Output I need:
DEFAULT MESSAGE
waits diff_time
file1.txt content
waits 5 seconds
DEFAULT MESSAGE
waits diff_time
file2.txt content
waits 7 seconds
DEFAULT MESSAGE
waits diff_time
file3.txt content
waits 3 seconds
ENDS
It also does not work well if I have two files with the same time, such as this:
order.txt
file1.txt;5;15:01
file2.txt;6;15:01
file3.txt;3;15:02
It breaks it aswell.
Any idea of how to do this correctly?
As commented above by #M Oehm, it is apparent the compiler warnings are not fully enabled. Suggest enabling them - it will save you time.
A problem lies in the time compare and subtraction.
// Troublesome code
if(currentTime->tm_hour < hour && currentTime->tm_min < min) {
diff_time = difftime(currentTime,timeValue);
printf("%d - Or this?\n", diff_time);
sleep(diff_time);
}
The comparison is curious. Usually with such a comparison would be in the form
if (h1 < h2 || (h1 == h2 && m1 < m2))
difftime takes 2 time_t paramters, not char timeValue[50] and a struct tm.
The values passed to double difftime(time_t time1, time_t time0) appear backwards. The result it time1 - time0.
Recommend instead
int current_hm = currentTime->tm_hour * 60 + currentTime->tm_min;
int file_hm = hour * 60 + min;
if (current_hm < file_hm) {
unsigned diff_time = (file_hm - current_hm)*60u;
printf("%u - Or this?\n", diff_time);
sleep(diff_time);
}
[Edit]
Simplified approach.
time_t now;
time(&now);
struct tm file_time_tm;
file_time_tm = *localtime(&now);
file_time_tm.tm_hour = hour; // from file
file_time_tm.tm_min = min; // from file
file_time_tm.tm_sec = 0;
file_time_tm.tm_isdst = -1;
time_t filetime = mktime(&file_time_tm);
double diff = difftime(filetime, now); // filetime - now
if (diff > 0) {
sleep((unsigned) diff);
}
Chux's suggestion to do your comparisons with your own integer that represents the minutes after midnight is probably easier in your case, but if you want to use the standard time mechanisms, you can do it.
But first, keep in mind that there are two time representations, time_t, which is a "numerical" time that stores the seconds after the epoch and struct tm, which is the human-readable time that breaks a time down to years, months, days and so on.
With strptime, you can scan a string accoding to a format specification. It is the scanf for struct tm. This function does not initialise fields that are not specified, so that you can assign the current time with localtime and then overwrite only the hour and minute fields.
mktime converts a struct tm to a time_t, which you can pass to difftime.
The following code snipped shows how such a comparison might work:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main()
{
char stamp[] = "12:53";
char *p;
struct tm now;
time_t t = time(NULL);
now = *localtime(&t);
p = strptime(stamp, "%H:%M", &now);
if (p == NULL || *p != '\0') {
printf("Illegal date.\n");
} else {
char buf[20];
double dsec;
int dmin;
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M\n", &now);
puts(buf);
dsec = difftime(t, mktime(&now));
printf("Diff: %g sec\n", dsec);
dmin = (int) dsec / 60;
printf("Diff: %d min\n", dmin);
}
return 0;
}

Printing out current date

Implement a function that determines and prints out the current year, month and day. For example:
Today is 03/04/2014.
Code so far that I have:
#include <stdio.h>
#include <time.h>
int main ()
{
int days, weeks, months, years, option, rmd, currentyear, currentmonth;
int daysinjan, daysinfeb, daysinmarch;
time_t seconds;
seconds = time(NULL);
days = seconds/(60*60*24);
weeks = seconds/((60*60*24)*7);
rmd=seconds%31557600;
months = ((seconds/31557600) * 12)+(((float)rmd/31557600)*12);
years = days/(365.25);
currentyear = 1970 + years;
currentmonth = (((float)rmd/31557600)*12)+1;
printf("%ld/%ld", currentmonth,currentyear);
return 0;
}
Please do not mind all the useless stuff in the code, this question is part of a project and i simply used the code from my previous question to try and work with that code in order to solve this question. The problem i have is that i cannot print the current day of the month that it is, because of this i feel that i have gone about this question wrongly.
This uses standard library calls to do all the math for you.
From Here:
#include <time.h>
#include <stdio.h>
#define SIZE 256
int main (void)
{
char buffer[SIZE];
time_t curtime;
struct tm *loctime;
/* Get the current time. */
curtime = time (NULL);
/* Convert it to local time representation. */
loctime = localtime (&curtime);
/* Print out the date and time in the standard format. */
fputs (asctime (loctime), stdout);
/* Print it out in a nice format. */
strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime);
fputs (buffer, stdout);
strftime (buffer, SIZE, "The time is %I:%M %p.\n", loctime);
fputs (buffer, stdout);
return 0;
}
If you wanted to create this as a function to return a string, you could do it like this:
char * getTimeString (char *str)
{
//replace this comment with relevant code from above with (at least) two additional lines:
strcpy(str, buffer);
return str;
}
Call it like this:
int main(void)
{
char *timeStr;
timeStr = malloc(30);//sufficient length to accept values assigned in getTimeString()
printf("%s\n", getTimeString(timeStr);
free(timeStr);
return 0;
}
#include <time.h> // for time_t
#include <stdio.h> // for printf
int main () {
int days, weeks, months, years, option, rmd, currentyear, currentmonth;
int daysinjan, daysinfeb, daysinmarch;
time_t seconds;
seconds = time(NULL);
days = seconds/(60*60*24);
weeks = seconds/((60*60*24)*7);
rmd=seconds%31557600;
months = ((seconds/31557600) * 12)+(((float)rmd/31557600)*12);
years = days/(365.25);
currentyear = 1970 + years;
currentmonth = (((float)rmd/31557600)*12)+1;
printf("%ld/%ld", currentmonth,currentyear);
return 0;
}

Need Help Programming in C comparing times together

i need some advice and help with a plugin i am writing for Nagios.
i am writing the plugin in C, but have no previous experience in the language except for minor amounts whilst trying to get this plugin to work.
basically what i am trying to-do is the following.
read a text file that is generated on a remote PC by an application i have written, this program writes nothing more than 5 characters into the file, the first 4 chars are the time in 24 hour format. e.g. 22:30 > 10:30pm
it then needs to take these 4 characters convert them into a time and compare it to the current system time (if there is a difference of 5 mins then it generates a reply to nagios to flag a warning).
I have tried many different ways of doing this, my first attempt was to convert the characters into an integer, then convert the time into an integer and compare the difference .. failed at doing this.
my second attempt is to generate two Time Structs one with the current time in and the other with my "homemade" time in and compare them but this is not working either.
heres my code, no matter what i try the date from the file is always the same as the current system time, i know its something to-do with having to set the time at the top.
t_of_file = time(NULL);
time_from_file = localtime(&t_of_file);
but if i do not do this i get a segmentation fault.
heres the code.
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
struct tm *time_from_file;
struct tm *the_system_time;
time_t t_of_file;
time_t t_of_sys;
t_of_sys = time(NULL);
the_system_time = localtime(&t_of_sys);
t_of_file = time(NULL);
time_from_file = localtime(&t_of_file);
time_from_file->tm_year = the_system_time->tm_year;
time_from_file->tm_mon = the_system_time->tm_mon;
time_from_file->tm_mday = the_system_time->tm_mday;
time_from_file->tm_hour = 10; //should be read in from file
time_from_file->tm_min = 30; //should be read in from file
time_from_file->tm_sec = the_system_time->tm_sec;
time_from_file->tm_isdst = the_system_time->tm_isdst;
t_of_file = mktime(time_from_file);
printf("%s\n",ctime(&t_of_file));
t_of_sys = mktime(the_system_time);
printf("%s\n",ctime(&t_of_sys));
double difference = difftime(t_of_file, t_of_sys );
printf("%lf\n",(double)t_of_file);
printf("%lf\n",(double)t_of_sys);
if (difference >= 0.0) { //this should be 5 mins, not quite sure what to put here yet
// second is later than first
printf("later\n");
}
else if (difference < 0.0) {
// second is earlier than first
printf("earlier\n");
}
printf("%lf\n", difference);
return 0;//STATE_OK;
}
any help you can offer would be appreciated on this.
Following the answers i got, PACE's answer was spot on for what i wanted to-do and now i have a simpler bit of code that works perfectly for what i am trying to-do and is easier to under stand. below is the code in its modified form (it compiles perfectly on Linux btw).
#include <stdio.h>
#include <time.h>
int main ()
{
time_t filetime;
time_t presenttime;
struct tm * timeinfo;
time ( &filetime );
time ( &presenttime);
timeinfo = localtime ( &filetime );
timeinfo->tm_hour = 14; //this should be entered from file
timeinfo->tm_min = 15; //this should be entered from file
filetime = mktime ( timeinfo );
printf("my time %s\n",ctime(&filetime));
printf("pc time %s\n",ctime(&presenttime));
double difference = difftime(filetime, presenttime );
printf("%lf\n",(double)filetime);
printf("%lf\n",(double)presenttime);
if (difference > 300.0) {
// second is later than first
printf("later\n");
}
else if (difference < 0.0) {
// second is earlier than first
printf("earlier\n");
}
printf("%lf\n", difference);
return 0;
cheers for the help guys.
There is an example of making a time here. You can then compare the times with the difftime method.
If it were me, I'd be tempted to just save the result of time() to the file. That would save a whole lot of string parsing work on the other side.
I modified your code as follows and it does now what you were expecting:
struct tm time_from_file;
struct tm the_system_time;
time_t t_of_file;
time_t t_of_sys;
t_of_sys = time(NULL);
memcpy(&the_system_time,localtime(&t_of_sys),sizeof(struct tm));
t_of_file = time(NULL);
memcpy(&time_from_file,localtime(&t_of_sys),sizeof(struct tm));
time_from_file.tm_hour = 10; //should be read in from file
time_from_file.tm_min = 30; //should be read in from file
t_of_file = mktime(&time_from_file);
printf("%s\n",ctime(&t_of_file));
printf("%s\n",ctime(&t_of_sys));
double difference = difftime(t_of_file, t_of_sys );
printf("%lf\n",(double)t_of_file);
printf("%lf\n",(double)t_of_sys);
printf("%lf\n", difference);
What was wrong with your code:
You were using and modifying the pointer returned by localtime which happens to be same in both cases.
Consequently your pointers time_from_file and the_system_time were infact pointing to the same location.Any modification of one modifies the other as well and finally you have a difference of zero.
(Thanks gdb for helping me figure out that!!:D)
Paring your format is easy in C. Use this to read the time components from the file:
int hr, min;
fscanf (file, "%d:%d", &hr, &min);
Here is a complete solution:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
struct HrMin_ {
int hr;
int min;
};
typedef struct HrMin_ HrMin;
static const double TIME_DIFFERENCE = (double) (5 * 1000);
static HrMin read_time (FILE* file);
int
main (int argc, char **argv)
{
time_t sys_time_t = 0;
struct tm *sys_time = NULL;
struct tm *file_time = NULL;
double d = 0.0f;
if (argc != 2)
{
printf ("Usage: time_cmp <time_file>\n");
return 1;
}
time (&sys_time_t);
sys_time = localtime (&sys_time_t);
file_time = malloc (sizeof (struct tm));
file_time->tm_sec = sys_time->tm_sec;
file_time->tm_min = sys_time->tm_min;
file_time->tm_hour = sys_time->tm_hour;
file_time->tm_mday = sys_time->tm_mday;
file_time->tm_mon = sys_time->tm_mon;
file_time->tm_year = sys_time->tm_year;
file_time->tm_wday = sys_time->tm_wday;
file_time->tm_yday = sys_time->tm_yday;
file_time->tm_isdst = sys_time->tm_isdst;
FILE *file = fopen (argv[1], "r");
if (file == NULL)
{
printf ("Failed to open file: %s\n", argv[1]);
return 1;
}
HrMin hr_min = read_time (file);
fclose (file);
file_time->tm_hour = hr_min.hr;
file_time->tm_min = hr_min.min;
d = difftime (sys_time_t, mktime (file_time));
free (file_time);
if (d < 0) d *= -1;
printf ("Diff: %f\n", d);
if (d >= TIME_DIFFERENCE)
printf ("WARN!\n");
return 0;
}
static HrMin
read_time (FILE *file)
{
HrMin hr_min;
hr_min.hr = 0;
hr_min.min = 0;
fscanf (file, "%d:%d", &hr_min.hr, &hr_min.min);
return hr_min;
}

Resources