C - calculate all dates from Year X to Year Y - c

Please IGNORE, incompetence as its best!
Just messing with some basic file i/o really, in some nested for Loops but the output isn't quite what I want, though I can't seem to get it working.
#include <stdio.h>
int main(void) {
FILE *pFile;
pFile = fopen("dates.txt", "w");
int day, month, year;
for(day = 1; day <= 31; day++) {
for(month = 1; month <= 12; month++) {
for(year = 1900; year <= 2050; year++) {
if(day < 10 && month < 10) {
fprintf(pFile, "0%d/0%d/%d\n", day, month, year);
}else {
fprintf(pFile, "%d/%d/%d\n", day, month, year);
}
}
}
}
return 0;
}
Any tips much appreciated! And as a heads up, this isn't an homework task, just some experimentation really.
Cheers.

You can use mktime to create a date. Then add 1 day to it and create the next date.
This way you can iterate.
Following code shows first 200 dates.
#include <time.h>
#include <stdio.h>
int main(){
struct tm *lt;
int i=200;
//time_t t=0; // first second on epoch
time_t t=-2209010000; // first second on 1900 (works on GCC, dind't test MSVS compiler)
while(i--){
lt = localtime(&t);
printf("YYYY:MM:DD = %04d:%02d:%02d\n", lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday);
lt->tm_hour+=24; // adding 24 hours
t = mktime(lt);
}
return 0;
}
By the way it works dates behind epoch. At least on my gcc version 4.4.3 in x86_64 GNU/Linux

You can actually have 4 combinations of day and month in which you may or may not prefix with 0, which you are trying to handle with single if else.
Case 1: Both day and month <10, handled by first if.
Case 2: Day > 10 and Month < 10, un-handled
Case 3: Day < 10 and Month > 10, un-handled
Case 4: Both are > 10. Handled in else.
%02d is the option to handle all the cases.

You probably want the year loop before the month loop before the day loop (the reverse of the current order).
You are going to need to make the testing for maximum day of the month cleverer (you need to know the rules for leap years (noting that 1900 was not a leap year, pace MS Excel, and 2000 was).
You can use %02d or %.2d to print 2 digits for the month and day, so you only need a single printf() statement.

Related

How can i add a certain number of days to a current date in c

I've been trying to add a certain number of days (I'm trying to add 30) to the current date.
Let's say today's date is 1/1/2023, after adding the number of days I want to add, I would get 31/1/2023, the main problem would be if I wanted to add if February has 29 days instead of 28.
I got the current date, couldn't add the number of days I wanted because I don't know other way to get the current date without the format being like this "Sun Jan 01 16:29:19 2023".
Just a side note, I saw people adding x days to a date using c, but those problem had the user inserting the date they wanted to the problem, my problem is adding it to the CURRENT DATE.
Anyone can help me with this one?
The standard library time functions already know about leap years and number of days in a month etc. So it makes sense to use that calendrical "expertise".
This is a "duplicate" of my answer at Algorithm to add or subtract days from a date? but adapted slightly to remove the C++ specifics (hence not marking it as a duplicate). Other answers there may be adapted of course.
#include <time.h>
// Adjust date by a number of days +/-
void DatePlusDays( const struct tm* date, int days )
{
const time_t ONE_DAY = 24 * 60 * 60 ;
// Seconds since start of epoch
time_t date_seconds = mktime( date ) + (days * ONE_DAY) ;
// Update caller's date
// Use localtime because mktime converts to UTC so may change date
*date = *localtime( &date_seconds ) ;
}
Regarding:
"I saw people adding x days to a date using c, but those problem had the user inserting the date they wanted to the problem, my problem is adding it to the CURRENT DATE."
So surely you need only supply the current date as the input. No need to restrict the solution to be quite so inflexible.
Example usage for "current date":
#include <stdio.h>
#include <time.h>
int main( void )
{
struct tm today ;
today = *localtime( time(NULL) ) ;
// Date, plus 30 days
DatePlusDays( &today, 30 ) ;
// Show time/date using default formatting
printf( "%s\n", asctime( &today) ) ;
}
It can be used to subtract days too (pass negative days).
Of course, if you truly do want to restrict the solution to just the current date:
#include <time.h>
// Adjust date by a number of days +/-
const struct tm* TodayPlusDays( int days )
{
const time_t ONE_DAY = 24 * 60 * 60 ;
// Seconds since start of epoch
time_t date_seconds = time( NULL ) + (days * ONE_DAY) ;
// Update caller's date
// Use localtime because mktime converts to UTC so may change date
return localtime( &date_seconds ) ;
}
Example usage:
#include <stdio.h>
#include <time.h>
int main( void )
{
struct tm today = *TodayPlusDays( 30 ) ;
// Show time/date using default formatting
printf( "%s\n", asctime( &today) ) ;
}
Assuming you've already parsed the date into its component day, month, and year. We can "add days" with a very simple algorithm. And we can even subtract days (or add negative days).
Nothing below uses any of the standard libraries for managing date and time. Nothing against those solutions or the standard libraries. But I wanted to present a simple portable way with the Gregorian calendar that also takes leap years into account.
First a struct to indicate a Date:
struct Date
{
int day;
int month;
int year;
};
Then we need a little helper for leap years.
bool isLeapYear(int year)
{
// leap years happen on 4 year boundaries unless year is divisible by 100 and not 400
// 2000 was a leap year, but 2100 is not
if (year % 400 == 0) return true;
if (year % 100 == 0) return false;
return (year % 4 == 0);
}
And with this data structure for a Date and a leap year detection function, we can build a very simple solution. The basic algorithm is to increment a given date "one day at a time" until the number of added days has been achieved. Each time we increment the day member past the number of days in a month, it gets reset to 1 and the month member gets incremented. And similarly, we handle incrementing to the next year. And then adjust for leap years as well.
// adds "numberOfDays" to the date object pointed to by "d"
void AddDays(Date* d, int numberOfDays)
{
static const int daysInMonths[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const int daysInMonthsLeap[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int* monthTable = isLeapYear(d->year) ? daysInMonthsLeap : daysInMonths;
// handle the case where we are adding a positive number of days to "d"
while (numberOfDays > 0)
{
d->day++;
if (d->day > monthTable[d->month])
{
d->month++;
if (d->month > 12)
{
d->month = 1;
d->year++;
monthTable = isLeapYear(d->year) ? daysInMonthsLeap : daysInMonths;
}
d->day = 1;
}
numberOfDays--;
}
// handle the case where we are adding a negative number of days to "d".
while (numberOfDays < 0)
{
d->day--;
if (d->day <= 0)
{
d->month--;
if (d->month <= 0)
{
d->year--;
d->month = 12;
monthTable = isLeapYear(d->year) ? daysInMonthsLeap : daysInMonths;
}
d->day = monthTable[d->month];
}
numberOfDays++;
}
}
The above isn't the most efficient - especially if you are adding millions of days onto a given Date object. But for dealing with time adjustments in terms of a small number of days, weeks, or even less than a couple thousand years, you could do a lot worse. A quick benchmark in an optimized build shows that the above works reasonably fast for adding 5 million days to today's date to get to the year 16000 and later.
There's also plenty of opportunities for optimizations in the loops above.

ISO 8601 week number in C

I am trying to get the ISO8601 week number with C. MinGW is installed on my PC. GCC version is 5.3.0. You can see my code below. strftime doesn't work for specifier "%V". But it works fine with the specifier "%W". But that's not what I want. I need the week number of year in ISO 8601 format.
I have tried my code with 2 different online C compilers and they both worked fine. I doubt that the compiler on my PC is not well configured. Can anyone tell me what am I doing wrong? Any help would be appreciated.
Here is my code:
#include <stdio.h>
#include <time.h>
#include <string.h>
int main ()
{
time_t timep;
struct tm * time_inf;
char buff [80];
time ( &timep );
time_inf = localtime ( &timep );
time_inf->tm_year = 2008 - 1900;
time_inf->tm_mon = 11;
time_inf->tm_mday = 31;
mktime ( time_inf );
strftime (buff, sizeof(buff), "%V", time_inf) ;
puts (buff); //prints nothing
printf("%d", strlen(buff)); //prints 0
return 0;
}
to get the ISO8601 week number with C
When "%V" with strftime() is not available or problematic, code can directivity calculate the ISO 8601 week.
ISO 8601 weeks of the year begins on Mondays.
When one want to find the ISO 8601 week of the year, often the corresponding "year" is needed too.
The first week of the year, week #1, is the first week, starting on Monday, that has at least 4 days in January - or as code below uses, the first Thursday of the year is in week 1.
Is is possible that Dec 31 is in week 1 of the next year.
Is is possible that Jan 1 is in week 52/53 of the previous year.
#include <time.h>
// return 1 on failure, 0 on success
int tm_YearWeek(const struct tm *tmptr, int *year, int *week) {
// work with local copy
struct tm tm = *tmptr;
// fully populate the yday and wday fields.
if (mktime(&tm) == -1) {
return 1;
}
// Find day-of-the-week: 0 to 6.
// Week starts on Monday per ISO 8601
// 0 <= DayOfTheWeek <= 6, Monday, Tuesday ... Sunday
int DayOfTheWeek = (tm.tm_wday + (7 - 1)) % 7;
// Offset the month day to the Monday of the week.
tm.tm_mday -= DayOfTheWeek;
// Offset the month day to the mid-week (Thursday) of the week, 3 days later.
tm.tm_mday += 3;
// Re-evaluate tm_year and tm_yday (local time)
if (mktime(&tm) == -1) {
return 1;
}
*year = tm.tm_year + 1900;
// Convert yday to week of the year, stating with 1.
*week = tm.tm_yday / 7 + 1;
return 0;
}
Example
int main() {
struct tm tm = { 0 };
tm.tm_year = 2008 - 1900;
tm.tm_mon = 12 - 1;
tm.tm_mday = 31;
tm.tm_isdst = -1;
int y = 0, w = 0;
int err = tm_YearWeek(&tm, &y, &w);
printf("Err:%d Year:%d Week:%d %02d%02d\n", err, y, w, y%100, w);
return 0;
}
Output is week 1 of 2009 for Dec 31, 2008 or 0901. This is expected per the discussion above and may explain OP's unstated concern with OP's code.
Err:0 Year:2009 Week:1 0901
MinGW doesn't provide its own strftime, but links in MSVCRT's definition, which doesn't provide %V.
Either implement what you're missing yourself or use an alternate implementation, e.g. here's BSD's strftime.

Print current date, without complex time commands

The prompt is:
Implement a function that determines and prints out the current year, month and day.
For example:
Today is 03/04/2014.
You guys dont have to really mind the code i wrote, its just kinda like scribble trying to figure our a way to print the current date using the seconds since the epoch given by the
time(NULL) command.
Before anyone gives me a super complex time command code etc etc, im pretty sure my professor wants us to convert the unix time (seconds since the epoch: jan 1, 1970) to the current date somehow.
Would anyone be able to help me in anyway to do this in the way my professor wants?
Thanks!
The code i currently have is:
#include <stdio.h>
#include <time.h>
int main ()
{
int days, weeks, months, years, option, rmd, currentyear, currentmonth;
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;
}
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t now = time(0);
struct tm *t = localtime(&now);
printf("%.4d-%.2d-%.2d\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
return 0;
}
Dealing with dates the naive way is a suicide*, use the localtime function. It will still get something wrong (dates are a horrible hideous mess that just cannot be got completely right), but at least the "nornal" stuff is already taken care of, and it's someone else's fault anyhow.
*your code is not handling leap years, so your result is completely wrong. So you add the code to check for years multiple if four. But then dates before 1900 are wrong, because century boundaries are an exception (they aren't leap years). And then dates after 2000 are all wrong, because there's an exception to the exception, and years divisible by 400 are leap years anyway. And we haven't started talking about time zones, DST and leap seconds.

Convert unix timestamp to date without system libs

I am building a embedded project which displays the time retrieved from a GPS module on a display, but I would also like to display the current date. I currently have the time as a unix time stamp and the progject is written in C.
I am looking for a way to calculate the current UTC date from the timestamp, taking leap years into account? Remember, this is for an embedded project where there is no FPU, so floating point math is emulated, avoiding it as much as possible for performance is required.
EDIT
After looking at #R...'s code, I decided to have a go a writing this myself and came up with the following.
void calcDate(struct tm *tm)
{
uint32_t seconds, minutes, hours, days, year, month;
uint32_t dayOfWeek;
seconds = gpsGetEpoch();
/* calculate minutes */
minutes = seconds / 60;
seconds -= minutes * 60;
/* calculate hours */
hours = minutes / 60;
minutes -= hours * 60;
/* calculate days */
days = hours / 24;
hours -= days * 24;
/* Unix time starts in 1970 on a Thursday */
year = 1970;
dayOfWeek = 4;
while(1)
{
bool leapYear = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
uint16_t daysInYear = leapYear ? 366 : 365;
if (days >= daysInYear)
{
dayOfWeek += leapYear ? 2 : 1;
days -= daysInYear;
if (dayOfWeek >= 7)
dayOfWeek -= 7;
++year;
}
else
{
tm->tm_yday = days;
dayOfWeek += days;
dayOfWeek %= 7;
/* calculate the month and day */
static const uint8_t daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for(month = 0; month < 12; ++month)
{
uint8_t dim = daysInMonth[month];
/* add a day to feburary if this is a leap year */
if (month == 1 && leapYear)
++dim;
if (days >= dim)
days -= dim;
else
break;
}
break;
}
}
tm->tm_sec = seconds;
tm->tm_min = minutes;
tm->tm_hour = hours;
tm->tm_mday = days + 1;
tm->tm_mon = month;
tm->tm_year = year;
tm->tm_wday = dayOfWeek;
}
First divide by 86400; the remainder can be used trivially to get the HH:MM:SS part of your result. Now, you're left with a number of days since Jan 1 1970. I would then adjust that by a constant to be the number of days (possibly negative) since Mar 1 2000; this is because 2000 is a multiple of 400, the leap year cycle, making it easy (or at least easier) to count how many leap years have passed using division.
Rather than trying to explain this in more detail, I'll refer you to my implementation:
http://git.musl-libc.org/cgit/musl/tree/src/time/__secs_to_tm.c?h=v0.9.15
Here's a portable implementation of mktime(). It includes support for DST that you might remove in order reduce the size somewhat for UTC only. It also normalizes the data (so if for example you had 65 seconds, it would increment the minute and set the seconds to 5, so perhaps has some overhead that you don't need.
It seems somewhat more complex than the solution you have arrived at already; you may want to consider whether there is a reason for that? I would perhaps implement both as a test (on a PC rather than embedded) and iterate through a large range of epoch time values and compare the results with the PC compiler's own std::mktime (using C++ will avoid the name clash without having to rename). If they all produce identical results, then use the fastest/smallest implementation as required, otherwise use the one that is correct!
I think that the typical library mktime performs a binary convergence comparing the return of localtime() with the target. This is less efficient than a direct calendrical calculation, but I presume is done to ensure that a round-trip conversion from struct tm to time_t (or vice versa) and back produces the same result. The portable implementation I suggested above uses the same convergence technique but replaces localtime() to remove library dependencies. On reflection therefore, I suspect that the direct calculation method is preferable in your case since you don't need reversibility - so long as it is correct of course.

How to decompose unix time in C

This seems like something no one should ever have to do, but I'm working on a kernel module for an embedded system (OpenWRT) in which it seems that time.h does include the timespec and time_t types, and the clock_gettime and gmtime functions, but does not include localtime, ctime, time, or, critically, the tm type.
When I attempt to cast the return pointer from gmtime to my own struct, I get a segfault.
So I guess I'd be content to solve the problem either of two ways—it'd be great to figure out how to get access to that missing type, or alternatively, how to roll my own method for decomposing a unix timestamp.
This should be accurate (fills out a cut-down imitation of a struct tm, my year uses Common Era instead of a 1900 CE epoch):
struct xtm
{
unsigned int year, mon, day, hour, min, sec;
};
#define YEAR_TO_DAYS(y) ((y)*365 + (y)/4 - (y)/100 + (y)/400)
void untime(unsigned long unixtime, struct xtm *tm)
{
/* First take out the hour/minutes/seconds - this part is easy. */
tm->sec = unixtime % 60;
unixtime /= 60;
tm->min = unixtime % 60;
unixtime /= 60;
tm->hour = unixtime % 24;
unixtime /= 24;
/* unixtime is now days since 01/01/1970 UTC
* Rebaseline to the Common Era */
unixtime += 719499;
/* Roll forward looking for the year. This could be done more efficiently
* but this will do. We have to start at 1969 because the year we calculate here
* runs from March - so January and February 1970 will come out as 1969 here.
*/
for (tm->year = 1969; unixtime > YEAR_TO_DAYS(tm->year + 1) + 30; tm->year++)
;
/* OK we have our "year", so subtract off the days accounted for by full years. */
unixtime -= YEAR_TO_DAYS(tm->year);
/* unixtime is now number of days we are into the year (remembering that March 1
* is the first day of the "year" still). */
/* Roll forward looking for the month. 1 = March through to 12 = February. */
for (tm->mon = 1; tm->mon < 12 && unixtime > 367*(tm->mon+1)/12; tm->mon++)
;
/* Subtract off the days accounted for by full months */
unixtime -= 367*tm->mon/12;
/* unixtime is now number of days we are into the month */
/* Adjust the month/year so that 1 = January, and years start where we
* usually expect them to. */
tm->mon += 2;
if (tm->mon > 12)
{
tm->mon -= 12;
tm->year++;
}
tm->day = unixtime;
}
My apologies for all the magic numbers. 367*month/12 is a neat trick to generate the 30/31 day sequence of the calendar. The calculation works with years that start in March until the fixup at the end, which makes things easy because then the leap day falls at the end of a "year".
In userspace glibc will do a lot of work with regards to handling the "local" part of time representation. Within the kernel this is not available. Probably you should not try to bother with this within your module, if needed do it in userspace.
A time_t is the number of seconds since Jan 1, 1970 UTC so decomposing that into month, day, and year isn't that difficult provided that you want the result in UTC. There is a bunch of source available by Googling "gmtime source". Most embedded systems leave out local time processing since it is a little more difficult due to the reliance on timezone setting and the environment.

Resources