The 2nd answer in How do I convert "2012-03-02" into unix epoch time in C? does provides the solution. But it uses tm_yday instead of tm_mday and tm_mon of tm structure.
My Input is human readable date and time and the desired output is UNIX epoch time.
int main(int argc, char *argv[])
{
char timeString[80] = {"05 07 2021 00 33 51"}; //epoch is 1620347631000
struct tm my_tm = {0};
if(sscanf(timeString, "%d %d %d %d %d %d", &my_tm.tm_mon, &my_tm.tm_mday, &my_tm.tm_year, &my_tm.tm_hour, &my_tm.tm_min, &my_tm.tm_sec)!=6)
{
/* ... error parsing ... */
printf(" sscanf failed");
}
// In the below formula, I can't use my_tm.tm_yday as I don't have the value for it.
//I want to use my_tm.tm_mday and tm_mon.
printf("%d",my_tm.tm_sec + my_tm.tm_min*60 + my_tm.tm_hour*3600 + my_tm.tm_yday*86400 +
(my_tm.tm_year-70)*31536000 + ((my_tm.tm_year-69)/4)*86400 -
((my_tm.tm_year-1)/100)*86400 + ((my_tm.tm_year+299)/400)*86400 );
return EXIT_SUCCESS;
}
So, in other words, I'm looking for a replacement for my_tm.tm_yday*86400 in terms of my_tm.tm_mday and my_tm.tm_mon
A year in the range "date of adoption of Gregorian calendar" to INT_MAX and a month in the range 1 to 12 can be converted to a zero-based "year day" in the range 0 to 365 by the following helper function:
int yday(int year, int month)
{
static const short int upto[12] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
int yd;
yd = upto[month - 1];
if (month > 2 && isleap(year))
yd++;
return yd;
}
That uses the following helper function isyear that takes a year in the range "date of adoption of Gregorian calendar" to INT_MAX and returns 0 if the year is not a leap year, 1 if the year is a leap year:
int isleap(int year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
Related
In my program, I am asking the user to input a date (in just integers such as 12 31 2019 367) and the number of days they add to it. In one of my functions, this is precisely what I am doing.
The user inputs 12 31 2019 367, and the program is meant to print 1 1 2021, but instead prints 1 1 2020 (a year behind)...
What I did (sorry for a lot of code, I tried to keep it simple and clean):
int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
void add_days_to_date(int *mm, int *dd, int *yy, int days_left_to_add)
{
int days_left_in_month;
while(days_left_in_month > 0)
{
days_left_in_month = days_in_month[*mm] - *dd;
// days_left_in_month = days_in_month[*mm] - *dd;
if (days_in_month[2] && is_leap_year(*yy) == true)
{
days_left_in_month++;
}
} // end while
printf("after while\n");
if(days_left_to_add > days_left_in_month)
{
days_left_to_add -= days_left_in_month;
*dd = 1;
if(*mm == 12)
{
*mm = 1;
(*yy)++;
}
else
{
(*mm)++;
}
}
else
{
*dd += days_left_to_add;
days_left_to_add = 0;
}
}
int main()
{
int mm, dd, yy, days_left_to_add;
printf("Please enter a date between the years 1800 and 10000 in the format mm dd yy and provide the number of days to add to this date:\n");
scanf("%d %d %d %d", &mm, &dd, &yy, &days_left_to_add);
// printf("\nREAD\n");
//These are pointers, so they have to be at certain location i.e. int* mm = &mm
add_days_to_date(&mm, &dd, &yy, days_left_to_add);
printf("%d %d %d\n", mm, dd, yy);
}
What I got after inputs:
Inputs: 12 31 2019 367
Output: 1 1 2020 (meant to be 1 1 2021)
Your loop in the function needs to be while (days_left_to_add > 0), and should cover the whole of the function (and then needs some minor adjustments). As it is, you add just one month, which given that your input is 2019-12-31 lands you on 2020-01-01.
Your code should validate the input date.
This code works, at least for a number of test cases similar to your example.
/* SO 74925-5084 */
#include <stdio.h>
#include <stdbool.h>
static const int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static bool is_leap_year(int year)
{
if (year % 4 != 0)
return false;
if (year % 100 != 0)
return true;
if (year % 400 != 0)
return false;
return true;
}
static void add_days_to_date(int *mm, int *dd, int *yy, int days)
{
while (days > 0)
{
int days_left_in_month = days_in_month[*mm] - *dd + 1;
if (*mm == 2 && is_leap_year(*yy))
days_left_in_month++;
//printf("DAYS = %2d, DLIM = %2d, leap(%4d) = %s\n",
// days, days_left_in_month, *yy, is_leap_year(*yy) ? "true" : "false");
if (days >= days_left_in_month)
{
days -= days_left_in_month;
*dd = 1;
if (*mm == 12)
{
*mm = 1;
(*yy)++;
}
else
{
(*mm)++;
}
}
else
{
*dd += days;
days = 0;
}
// This is informative while debugging
printf("%.4d-%.2d-%.2d + %d\n", *yy, *mm, *dd, days);
}
}
int main(void)
{
int mm, dd, yy, days_left_to_add;
printf("Please enter a date between the years 1800 and 10000 in the format mm dd yyyy\n"
"and provide the positive number of days to add to this date:\n");
if (scanf("%d %d %d %d", &mm, &dd, &yy, &days_left_to_add) != 4)
{
fprintf(stderr, "Failed to read 4 numbers\n");
return 1;
}
printf("Input: %.4d-%.2d-%.2d + %d\n", yy, mm, dd, days_left_to_add);
/* Data validation */
if (days_left_to_add <= 0)
{
fprintf(stderr, "The number of days to add must be a positive number (unlike %d)\n",
days_left_to_add);
return 1;
}
if (yy < 1800 || yy > 10000)
{
fprintf(stderr, "Year %d is outside the range 1800..10000\n", yy);
return 1;
}
if (mm < 1 || mm > 12)
{
fprintf(stderr, "Month %d is outside the range 1..12\n", mm);
return 1;
}
int dim = days_in_month[mm];
if (mm == 2 && is_leap_year(yy))
dim++;
if (dd < 1 || dd > dim)
{
fprintf(stderr, "Day %d is outside the range 1..%d\n", dd, dim);
return 1;
}
add_days_to_date(&mm, &dd, &yy, days_left_to_add);
printf("%d %d %d\n", mm, dd, yy);
return 0;
}
Sample runs (program ad41 created from ad41.c):
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2019 367
Input: 2019-12-31 + 367
2020-01-01 + 366
2020-02-01 + 335
2020-03-01 + 306
2020-04-01 + 275
2020-05-01 + 245
2020-06-01 + 214
2020-07-01 + 184
2020-08-01 + 153
2020-09-01 + 122
2020-10-01 + 92
2020-11-01 + 61
2020-12-01 + 31
2021-01-01 + 0
1 1 2021
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2018 60
Input: 2018-12-31 + 60
2019-01-01 + 59
2019-02-01 + 28
2019-03-01 + 0
3 1 2019
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2019 60
Input: 2019-12-31 + 60
2020-01-01 + 59
2020-02-01 + 28
2020-02-29 + 0
2 29 2020
$
I am new here, please bear with me for any blunders.
I am trying to convert the time in GMT format to Unix Epoch (starting from 1970).
The procedure i am following for this is to, iterate over the years starting from 1970 till the given date finding out number of leap years and normal years and multiplying the number of days accordingly.
Then adding the number of days passed in a month, add day value and hours, minutes seconds from tm structure, as shown in below code.
The code is not working as expected , and i seem to be lost in some calculations, and i don't understand what it is.
Followig are the inputs i am trying , expected and actual output is provided here.
Normal years:
Input: Jan 20 19:00:01 2019 GMT
Expected output: 1548010801
Actual output: 1548097201 (which is Jan 21 19:00:01 2019 GMT, 1 day difference)
Leap Years:
Input: Dec 27 14:52:30 2020 GMT
Expected output: 1609080750
Actual output: 1609253550 (which is Dec 29 14:52:30 2020 GMT, 2 days difference)
I request help in finding the problem.
I have two Open Questions
1)I am not sure whether i need to worry about DST or not because i am getting the time as input in GMT format.
2)Is there a better way to calculate the epoch using some formulas expressions , rather than iterating and manually
calculating.
There is already one existing post for same
but it is using mktime and difftime.
I want to know what is the problem in my code and any better way to do in formulas expressions.
#include <stdio.h>
#include <string.h>
#include <time.h>
#define BASE_YEAR 1970
void print_time_readable_format(struct tm tm);
int convert_gmt_date_time_to_tm_format(char* gmt_time_fmt);
int check_year_is_leap_or_normal(int year);
int get_number_of_leap_years_from_base_year(int start_year, int end_year);
int convert_gmt_to_epoch(struct tm tm);
int main()
{
int epoch = 0;
//char gmt_time_fmt[] = "Jan 20 19:00:01 2019 GMT";
char gmt_time_fmt[] = "Dec 27 14:52:30 2020 GMT";
//char gmt_time_fmt[] = "Jan 01 00:00:01 1970 GMT";
epoch = convert_gmt_date_time_to_tm_format(gmt_time_fmt);
printf("time in GMT = %s and epoch is %d\n", gmt_time_fmt, epoch);
return 0;
}
int convert_gmt_date_time_to_tm_format(char* gmt_time_fmt)
{
struct tm tm;
char tm_time_fmt[255];
//set tm struture to 0
memset(&tm, 0, sizeof(struct tm));
// convert gmt_time_fmt to format required by 'tm' structure
strptime(gmt_time_fmt, "%B %d %H:%M:%S %Y GMT", &tm);
strftime(tm_time_fmt, sizeof(tm_time_fmt), "%s", &tm);
printf("tm_time_fmt = %s\n", tm_time_fmt);
print_time_readable_format(tm);
return convert_gmt_to_epoch(tm);
return 0;
}
int convert_gmt_to_epoch(struct tm tm)
{
int days_by_month [2][12] = {
/* normal years */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
/* leap years */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};
int current_year = tm.tm_year+1900;
printf("current_year =%d\n", current_year);
int total_years_passed = current_year - BASE_YEAR;
printf("total_years_passed =%d\n", total_years_passed);
int nleap_years_passed = get_number_of_leap_years_from_base_year(BASE_YEAR, current_year);
int normal_years = total_years_passed - nleap_years_passed;
printf("normal_years =%d\n", normal_years);
int total_days_passed = (normal_years*365 + nleap_years_passed*366 );
printf("total_days_passed =%d\n", total_days_passed);
total_days_passed += days_by_month[check_year_is_leap_or_normal(current_year)][tm.tm_mon];
printf("total_days_passed after adding month =%d\n", total_days_passed);
total_days_passed += tm.tm_mday;
printf("total_days_passed after adding day =%d\n", total_days_passed);
total_days_passed = total_days_passed*24 + tm.tm_hour;
total_days_passed = total_days_passed*60 + tm.tm_min;
total_days_passed = total_days_passed*60 + tm.tm_sec;
printf("total_days_passed final =%d\n", total_days_passed);
return total_days_passed;
}
int get_number_of_leap_years_from_base_year(int start_year, int end_year)
{
int leap_year_count = 0;
int year = start_year;
while( year <= end_year)
{
if(check_year_is_leap_or_normal(year))
leap_year_count++;
year++;
}
printf("leap_year_count = %d\n", leap_year_count);
return leap_year_count;
}
int check_year_is_leap_or_normal(int year)
{
if( ( year%4 == 0 ) && ( ( year%400 == 0 ) || ( year%100 != 0)))
return 1;
else
return 0;
}
void print_time_readable_format(struct tm tm)
{
printf("tm.tm_year = %d ", tm.tm_year);
printf("tm.tm_mon = %d ", tm.tm_mon);
printf("tm.tm_mday = %d ",tm.tm_mday);
printf("tm.tm_hour = %d ", tm.tm_hour);
printf("tm.tm_min = %d ", tm.tm_min );
printf("tm.tm_sec = %d\n", tm.tm_sec );
}
Two calculation errors:
How leap year is counted, it must exclude the very last year. The correct one should be:
int nleap_years_passed = get_number_of_leap_years_from_base_year(BASE_YEAR, current_year - 1);
Total days passed must also exclude the end date. The revised formula:
total_days_passed += (tm.tm_mday - 1);
Above two formula has caused the epoch to be off by 1 day each.
I am a newbie to coding and I am trying to code for the "Friday the Thirteenth" problem posted in USACO, which requires us to compute the frequency that the 13th of each month lands on Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday over a given period of N years. The time period to test will be from January 1, 1900 to December 31, 1900+N-1 for a given number of years, N. N is positive and will not exceed 400.
It was given that Jan 1, 1900 was on a Monday. We are not supposed to use any in-built functions.
I tried to solve this problem with a different approach (which I think isn't the best approach). My code (in C) is given below:
#include<stdio.h>
int daysInMonth (int month, int year)
{
/*
30 should be returned if the months are Apr, June, Sept and Nov.
31 should be returned in all other cases.
29 should be returned if the month is Feb and the year is a leap year
*/
if (month == 1) //Feb
{
if (year % 4 == 0 || (year % 100 != 0 && year % 400 == 0)) //leap year
return 29;
else
return 28;
}
switch (month)
{
case 3:
case 5:
case 8:
case 10: return 30;
default: return 31;
}
}
void main ()
{
int month, year, n, i, noOfDays, start = 0, result[] = { 0, 0, 0, 0, 0, 0, 0 }, day = 0, daycheck = 1;
scanf ("%d", &n);
for (year = 1900; year <= 1900 + n - 1; ++year)
{
for (month = 0; month < 12; ++month)
{
if (month == 0 && year == 1900) // to identify the first 13th and the day it falls on
{
while (daycheck != 13)
{
++daycheck;
day = (day + 1) % 7;
}
++result[day];
}
else
{
if (month == 0) //If January, add the noOfDays of the prev. month i.e. December
noOfDays = 31;
else
noOfDays = daysInMonth (month - 1, year);
day += (noOfDays - 28); // Adding a multiple of 7 (here, 28) does not change the day
day %= 7;
++result[day];
}
}
}
for (i = 0; i < 7; ++i)
printf("%d ", result[(i + 5) % 7]); //Sat, Sun, Mon, Tue, Wed, Thu, Fri
}
For an input of 20, the expected output is 36 33 34 33 35 35 34.
However, my output turns out to be 35 35 33 35 32 35 35.
Even though my answer is within the range of the expected output, there's something wrong with my logic that makes it erroneous.
I would appreciate if someone could point out the error. I would also be happy if you could suggest a better way to approach this problem. I am a student of Computer Science and am yet to learn about algorithms in detail.
Your leap year condition is wrong.
Change the Leap year condition as follows.
int daysInMonth (int month, int year)
{
if (month == 1) //Feb
{
if (( year%400 == 0)|| (( year%4 == 0 ) &&( year%100 != 0)))
return 29;
else
return 28;
}
This simple program demonstrates the use of structures by determining tomorrow's date. It asks for an input of today's date:
#include <stdlib.h>
#include <stdio.h>
int main ( int argc, char *argv[] )
{
struct date {
int month;
int day;
int year;
}; /* ---------- end of struct date ---------- */
struct date today, tomorrow;
const int daysPerMonth[12] = { 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 };
printf ( "Enter today's date (mm dd yyyy): \n" );
scanf ( "%i%i%i", &today.month, &today.day, &today.year );
if ( today.day != daysPerMonth[today.month - 1] ) {
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}
else if ( today.month == 12 ) { /* end of year */
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}
else { /* end of month */
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
printf ( "Tomorrow's date is %i/%i/%.2i.\n", tomorrow.month,
tomorrow.day, tomorrow.year % 100 );
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
When running it, what I got:
Enter today's date (mm dd yyyy):
06 09 2014
Tomorrow's date is 6/1/09.
But when I run gdb and printed out the input values:
(gdb) p today.month
$1 = 6
(gdb) p today.day
$2 = 0
(gdb) p today.year
$3 = 9
I'm confused. Why is the input getting incorrect values like that?
Heh. The %i specifier for scanf means to read in a range of integer formats which is similar to that specified for C integer literals.
When you type a leading 0 it means that what follows are octal digits. Since 9 is not a valid octal digit, then just the value 0 is read. The 9 is left for the following %i, so the three numbers read are 6, 0, 9 , with 2014 remaining in the input stream.
To input in base 10 change the %i to %d, then your program will work.
You read the input as scanf ( "%i%i%i", &today.month, &today.day, &today.year );.
Since you prefix 0 in your input, they are treated as octal and thus lead to the result.
You should use scanf("%d%d%d", ...); instead.
I'm stuck on a program that takes the user's desired year and prints out a 12 month calendar for the same year. This is all I have so far and I'm pretty sure I have the right way to figure out whether the year is a leap year (in the code) and how to find out when the 1st of Jan is (underneath first with just variables then filled in). Also I am trying to print this in normal Calendar format with the month on top then the days of the week underneath followed by the day numbers. Any help would be appreciated.
Find first day:
h = (1 + [(13(m + 1))/5] + K + [K/4] + [J/4] - 2J) mod 7
h = (1 + [(13(13 + 1))/5] + (year % 100) + [(year % 100)/4] + [(year/100)/4] - 2(year/100) % 7
H is the starting day, M is the month, K is yr % 100, J is yr / 100.
/* Calendar.c */
#include <stdio.h>
int main(void){
int year, month, date;
int startingDay; /* initfrom user input*/
printf("Enter the year of your desired calendar: ");
scanf("%d\n", &year);
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
int months[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
else
int months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (month = 0; month < 12; month++) {
const int daysInMonth = ; /* set # of days */
int dayOfWeek;
printf(…); //month name
printf(…); //days of week
for (dayOfWeek = 0; dayOfWeek<startingDay; dayOfWeek++)
printf(/*blanks*/);
for (int date = 1; date <= daysInMonth; date++) {
printf("…", date);
if (++dayOfWeek>6) {
printf("\n");
dayOfWeek = 0;
}
} // for date
if (dayOfWeek !=0)
printf("\n");
startingDay = dayOfWeek;
} // for month
}
Output:
February 2009
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
The following compiles, but there are still opportunities for improvement:
/* calender.c */
#include <stdio.h>
#include <stdlib.h>
#define JULIAN 1
#define GREGORIAN 2
/*
* return the day of the week for particualr date
* flag JULIAN or GREGORIAN
* (the divisions are integer divisions that truncate the result)
* Sun = 0, Mon = 1, etc.
*/
int get_week_day(int day, int month, int year, int mode) {
int a, m, y;
a = (14 - month) / 12;
y = year - a;
m = month + 12*a - 2;
if (mode == JULIAN) {
return (5 + day + y + y/4 + (31*m)/12) % 7;
}
return (day + y + y/4 - y/100 + y/400 + (31*m)/12) % 7; // GREGORIAN
}
int main(void) {
int year, month, date;
int startingDay; /* of the week: init from user input*/
char *names[] = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
printf("Enter the year of your desired calendar: ");
scanf("%d", &year);
// could check whether input is valid here
startingDay = get_week_day(1, 1, year,GREGORIAN);
int months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
months[1] = 29;
for (month = 0; month < 12; ++month) {
const int daysInMonth = months[month]; /* set # of days */
int dayOfWeek, date;
printf("\n ------------%s-------------\n", names[month]); // month name
printf(" Sun Mon Tue Wed Thu Fri Sat\n"); // days of week
for (dayOfWeek = 0; dayOfWeek < startingDay; ++dayOfWeek)
printf(" ");
for (date = 1; date <= daysInMonth; ++date) {
printf("%5d", date);
if (++dayOfWeek > 6) {
printf("\n");
dayOfWeek = 0;
}
} // for date
if (dayOfWeek != 0)
printf("\n");
startingDay = dayOfWeek;
} // for month
return EXIT_SUCCESS;
}