How do I count backwards in days on the calendar?

Situation: I have a program that generates a log file each day at 8am in the format C:\2010\4\1\Example.txt (YYYY\M\D\Example.txt).  However, logs are not generated on weekends and holidays.

Ultimately, I would like to read the contents of the previous "X" number of days of Example.txts.  Specifically, I would like to count one day at a time backwards from today's date (up to X number of days), and find out if an Example.txt exists for that day (inspection by file existence).

Question 2)  Given today's date is 2010\4\1 how do I go backwards in time (by days) and create a filepath for 2009\3\31, 2009\3\2\30, etc...for X number of days?
LVL 1
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Commented:
>> up to X number of days
We can defer this initially since the main problem appears to be going backwards one day at a time.

Let's say that you have managed to get a date of yyyy, mm, dd as separate integers. That is:
unsigned short year;
unsigned short month;
unsigned short day;

Now your program logic would be to decrement day by 1. And if day is still positive (i.e., > 0) then you still have a valid year, month, day combination. If 0 and not January, then you have to decrement month by 1, and set the day to the last day of that month. If it's January 1, then the new date of course is Dec 31 of the previous year.

If you wanted to create a function, one_Day_Earlier() to do this, then you could have an input string of the form "2010\4\1", and it could return an output string of the form "2010\3\31".

BTW, if it is March, will your folder name be 3, or 03 (there may be an advantage to the latter when looking at a sorted directory listing).

So, try to post some code using the three integers with the logic described above. Then, the problem becomes about parsing the input string into the integers, and then constructing an output string; and then forming the new full file path name.
0
Author Commented:
The directory structure of the database is "C:\\YYYY\M\D\Example.txt" or "C:\\YYYY\MM\DD\Example.txt" for 2-digit days/months.  For example, March 18, 2010 data would be found in "C:\2010\3\18\Example.txt" and October 13,2009 data would be found in "C:\2009\10\10\Example.txt".

While I realize the sorting advantage to 03, I don't have control over that, and the program that generates logs uses 3 instead of 03.
0
Commented:
>> that generates logs uses 3 instead of 03.
No biggy.

Now, in all fairness to you, I did a little research. In the ".NET Framework Class Library" is a class called DateTime, and there are some methods (a method is like a function, but it belongs to a class) such as "Parse Method" which may assist you. These are not standard C++, but if you are using exclusively a compiler that can handle this, you may want to consider using these types of classes. While I may be able to read and suggest code; I will not be able to test it. But again, there are Experts in every field here. Here's a link to the Parse Method:
http://msdn.microsoft.com/en-us/library/1k1skd40(v=VS.80).aspx

See if you can come up with a simple piece of code that handles the three integers representing yyyy, mm, and dd, and decrement by 1. Post your code, ask any questions if you have problems, and then we'll move onto converting to/from strings.
0
Author Commented:
ok, this is my stab at it...btw, which time zone are you in? am wondering when i can expect to stop seeing replies...
``````void one_Day_Earlier(unsigned short year, unsigned short month, unsigned short day)
{
//months with 31 days: 1, 3, 5, 7, 8, 10, 12
//months with 30 days: 4, 6, 9, 11
//months with 28/29 days: 2
year = year - 1; //we will never count back before year 2000, so it's always positive

month = month - 1;
if (month == 0)  //if this month is Jan, prior month will be Dec.
{
month = 12;
}

day = day - 1; //decrement the day

if (day = 0) //if day = 0, today must be 1st of the month
{
if (month == 2 || month == 4 || month == 6 || month == 8 || month == 9 || month == 11 || month == 1)
{
day = 31;
}

if (month == 5 || month == 7 || month == 10 || month == 12)
{
day = 30;
}
if (month == 3 && (year % 4 == 0))  //leap year
{
day = 29;
}
if (month == 3 && (year % 4 != 0))  //not a leap year
{
day = 28;
}
}
}

int main()
{
unsigned short year;
unsigned short month;
unsigned short day;

year = 2010;
month = 3;
day = 31;

one_Day_Earlier(year, month, day);

return 0;
}
``````
0
Author Commented:
crap, as soon as i posted it i already see what i missed...need to decrement year only if today is Jan. 1, and decrement month only if day = 0 after day = day - 1.  am fixing it now.
0
Commented:
Good that you have a main test driver. How are you verifying your function is working the way you expect it to work?
0
Author Commented:
revised attempt:
``````void one_Day_Earlier(unsigned short year, unsigned short month, unsigned short day)
{
//months with 31 days: 1, 3, 5, 7, 8, 10, 12
//months with 30 days: 4, 6, 9, 11
//months with 28/29 days: 2
day = day - 1; //decrement the day

if (day = 0) //if day = 0, today must be 1st of the month
{
if (month == 2 || month == 4 || month == 6 || month == 8 || month == 9 || month == 11 || month == 1)
{
day = 31;
}

if (month == 5 || month == 7 || month == 10 || month == 12)
{
day = 30;
}
if (month == 3 && (year % 4 == 0))  //leap year
{
day = 29;
}
if (month == 3 && (year % 4 != 0))  //not a leap year
{
day = 28;
}

month = month - 1;
if (month == 0)  //if this month is Jan, prior month will be Dec.
{
month = 12;  //if we are in Dec., we must be in prior year...so...
year = year - 1; //we will never count back before year 2000, so it's always positive
}
}
}

int main()
{
unsigned short year;
unsigned short month;
unsigned short day;

year = 2010;
month = 3;
day = 31;

one_Day_Earlier(year, month, day);

return 0;
}
``````
0
Author Commented:
i am stepping through code...setting breakpoints. and looking at locals window...
0
Author Commented:
line 8 is fixed:
``````if (day == 0)
``````
0
Author Commented:
while the day INSIDE the one_day_earlier function is properly decremented from 3/31/10 to 3/30/10...when i return to the main function the day returns to 31 in the watch window..

i realize i'm leaving the local scope of the function...and that values were only copied into the one_day_earlier function and once i'm out of it day becomes 31 again.

how do i make it so that the one_day_earlier returns a string or filepath?
0
Author Commented:
and that it returns a decrement day (of 30) as opposed to becoming 31 again once we're out of the one_day_earlier function?
0
Commented:
>> if (day == 0)
In one of my projects having extremely strict coding standards that were audited under extreme scrutiny both internally and externally, we were not permitted to write the above line of code. It had to be written as:
if ( 0 == day )

Then, there is no chance of getting the program to build successfully if there is a = instead of a ==.
For some reason, we had to do things like
if ( 0 < day ) even though if( day > 0 ) would not have a problem like you had in line 8.

I'm guessing it was to establish a firm pattern of ( constant boolean_operator variable ).
0
Author Commented:
Ok.  Now that my code works in decrementing days in that function...what's the next step?  How do  Iget from that to a string/filepath?
0
Commented:
To have caught your = sign error is pretty advanced for a beginner with no programming experience. Maybe I misunderstood you. Are you experienced in Java or C, but limited in C++.

So, now you have three integers that represent a new date. Here's one way to convert to a c-style string using sprintf:
http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

char buffer[40];
sprintf( buffer, "%d\\%d\\%d", year, month, day);

Now instead of returning void, one_Day_Earlier can return a string (this is a C++ string, not a c-style string). Obviously there are different ways to handle this conversion. I picked one that is easiest to explain.

``````#include <string>

string one_Day_Earlier(...) {
//
char buffer[40];
sprintf( buffer, "%d\\\\%d\\\\%d", year, month, day);
return string(buffer);

}

// main
newdate = one_Day_Earlier(year, month, day);
``````
0

Experts Exchange Solution brought to you by

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Commented:
I'll be out for 1-2 hours. Will check back. If I can give a quick answer, I'll do that. Otherwise, there is always tomorrow.
0
Commented:
From your other related questions, you may have an idea of how to get those three input integers. Notice that in your one_Day_Earlier() function, you modified month, day, year and these new values did not get reflected back to your main() function. That is expected and desired behavior in this case. These three input variables were put on the one_Day_Earlier() stack and are now treated as local (auto variables) on the stack. All you did was change the values on the stack; and when you returned with the C++ string, the stack unwound, and that data is gone.
0
Author Commented:
regarding your 12:21am post.  i have no experience in C, Java, or C++.  i only caught that == error because my book explicitly says to watch out for it.  lucky me.

ok, i will try piecing everything together tomorrow morning to accomplish my initial goal.  thanks again for the guidance and help along the way.
0
Commented:
The simplest way to achieve this is to use Calendar and SimpleDateFormat.
Calendar myCal = Calendar.getInstance() gives you the current date.
- n is the number of days to go back
- there is a minus sign before to go back, if not add will...well add days, not remove them ;)

When you get your date, use the SimpleDateFormat :
SimpleDateFormat formatter  = new SimpleDateFormat("yyyyMMdd"); // or whatever format, just play with yyyy, MM and dd as you wish.
then format your date : String myFormattedDate = formatter.format(myCal.geTime());

And there you are !
0
Commented:
@vkphoenixfr:
I did a search, but I found java links. Could you post a corresponding C++ link for your suggestions.

@shaolinfunk:
>> (year % 4 == 0))  //leap year
this is almost right
http://en.wikipedia.org/wiki/Leap_year
But given that the first error occurs in 90 years, who cares?
Speaking of "who cares", you said in a previous related question that you don't care about leap years (or holidays, for that matter) since if the file does not exist, then you will simply skip over it (backwards).

So, using your algorithm, when you are on March 1, you could just consider the worst-case max days in February, which is 29. About 3 out of 4 times, you will have done an unnecessary file existence check. BTW, on a slow machine in mid 80's, I found that I could do about 100 file existence tests per second (for those who are concerned about performance). (Hmm, but given we are in Windows, maybe we better see if there's any degradation in that performance.)
0
Commented:
>> i have no experience in C, Java, or C++.  i only caught that == error because my book explicitly says to watch out for it.  lucky me.

Less luck than you may think IMO. For beginners, book warnings like that often go over their head - students often only focus on figuring out what to write, rather than what not to write. (Heck; for professionals, this = vs. == has bitten them many times!) So, I took a quick look at your other questions and found that years ago you did some VB work. This programming experience, no doubt, has enabled you to be at least an advanced beginner. (It's like riding a bike; you never have to start all over again, barring disabilities.) So, when you said in a related question, "Pretend that you are explaining this to an 11 year old 7th grader who is just starting to learn C++", I think you are underestimating yourself. I think we can up the level to at least that of an 8th grader, maybe even an 11th grader. Agreed?
0
Author Commented:
Hahahaha.  That VB stuff is so old it must have been back when I actually WAS in jr. high or high school.  I don't remember much from it and the only thing that has transferred over are the concepts like variables and if/then or for/next statements.

But yes, I can agree that I am an advanced beginner at an 8th grade level.  :)
0
Commented:
Sorry thought it was java.
Don't know why your question came out in my daily  alert on java :/
0
Commented:
@vkphoenixfr,
That is odd. Do you have anything else in your filter, or is strictly the java zone? If it continues, then you might want to bring it to the attention of community support to get a fix.
0
Commented:
@vkphoenixfr,
But thanks for your post! If I can get the author to write a C++ class (and I think he can without much difficulty), then we can take a look at the Java Calendar class api and consider copying the appropriate method api's like the ones you described.
0
Commented:
@phoffric,
You should, there are numbers of very handy classes to get inspiration from in the java world. I use theses Calendar/SimpleDateFormat with succes in business projects. You may want to have a look at apache commons (StringUtils, CollectionUtils, ConverterUtils, and so on...)

My filter was set like this : Any of these terms - java, j2ee - must appear in any part of the question
0
Commented:
@shaolinfunk,
Read vkphoenixfr's last post. During integration phase, you can create a Calendar class and start using methods instead of functions. For this class, there won't be much class magic. Not even sure we'll need to create an object of this class. That is the methods may stand alone and not have any state information in it. So, it may be a good way to introduce a simple class.

@vkphoenixfr:
Well, you asked for any reference to java in the thread, so look at: http:#29421175
You got what you asked for :)
I suppose you could use zone filters instead, but then you may miss the java calling c++ questions.
0
Commented:
damn, it was written "in the question" not "in the thread", right?
Well from now on i'll check the context more closely. Thanx !
0
Author Commented:
Hi Phoffric,

I'm stuck...can you help me out with this question:

http://www.experts-exchange.com/Programming/Languages/CPP/Q_25661997.html
0
Author Commented:
Hi,

I tried compiling your solution...but got some errors...am I missing something?
``````#include <time.h>
#include <stdio.h>
#include <string>

string one_Day_Earlier(unsigned short year, unsigned short month, unsigned short day)
{
//months with 31 days: 1, 3, 5, 7, 8, 10, 12
//months with 30 days: 4, 6, 9, 11
//months with 28/29 days: 2
day = day - 1; //decrement the day

if (day == 0) //if day = 0, today must be 1st of the month
{
if (month == 2 || month == 4 || month == 6 || month == 8 || month == 9 || month == 11 || month == 1)
{
day = 31;
}

if (month == 5 || month == 7 || month == 10 || month == 12)
{
day = 30;
}
if (month == 3)  //if not a leap year, who cares, just search, find nothing, skip, and decrement to 28
{
day = 29;
}

month = month - 1;
if (month == 0)  //if this month is Jan, prior month will be Dec.
{
month = 12;  //if we are in Dec., we must be in prior year...so...
year = year - 1; //we will never count back before year 2000, so it's always positive
}
}

char buffer[40];
sprintf( buffer, "%d\\\\%d\\\\%d", year, month, day);

return string(buffer);
}

int main()
{
// Get TODAY's date in string form

/* localtime example */

time_t rawtime;
struct tm * timeinfo;
char str[60];

time ( &rawtime );
timeinfo = localtime ( &rawtime );

strftime(str, sizeof(str) , "%Y %m %d", timeinfo);
printf(str);                                                //lets me see if date is right

// Get YESTERDAY's date
unsigned short year;
unsigned short month;
unsigned short day;

year = 2010;
month = 3;
day = 31;

//   newdate = one_Day_Earlier(year, month, day);

return 0;
}

1>Compiling...
1>Junk.cpp
1>c:\documents and settings\administrator\desktop\junk\junk\junk.cpp(5) : error C2146: syntax error : missing ';' before identifier 'one_Day_Earlier'
1>c:\documents and settings\administrator\desktop\junk\junk\junk.cpp(5) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\documents and settings\administrator\desktop\junk\junk\junk.cpp(6) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\documents and settings\administrator\desktop\junk\junk\junk.cpp(40) : error C2064: term does not evaluate to a function taking 1 arguments
1>c:\documents and settings\administrator\desktop\junk\junk\junk.cpp(40) : warning C4508: 'one_Day_Earlier' : function should return a value; 'void' return type assumed
1>Build log was saved at "file://c:\Documents and Settings\Administrator\Desktop\junk\junk\Debug\BuildLog.htm"
1>junk - 4 error(s), 1 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
``````
0
Commented:
Try adding after the include statements:
``````using namespace std;
``````
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.