Date Validation and Conversion in C++ - c++

I have to write 2 functions. One that takes in a date as a string and checks if its in mm/dd/yy format; if its not in the correct format, it should be edited to make it so. The other function should convert the validated date to the format "Month dd, 20yy".
I'm pretty sure I can take care of the second function, but I am having trouble with the first one. I just have no idea how to check if its in that format... any ideas?
I thought that this would work, but it doesn't seem to...
Updated code:
bool dateValidation(string shipDate)
{
string temp;
if(shipDate.length() == 8 )
{
if(shipDate[2] == '/' && shipDate[5] =='/')
{
int tempDay, tempMonth, tempYear;
//Gather month
temp = shipDate[0];
temp += shipDate[1];
//convert string to int
tempMonth = temp.atoi;
temp = "";
//Gather day
temp = shipDate[3];
temp += shipDate[4];
//convert string to int
tempDay = temp.atoi;
temp = "";
//Gather year
temp = shipDate[6];
temp += shipDate[7];
//convert string to int
tempYear = temp.atoi;
temp = "";
if(tempMonth > 0 && tempMonth <= 12)
{
if(tempMonth == 9 ||
tempMonth == 4 ||
tempMonth == 6 ||
tempMonth == 11 ||)
{
if(tempDay > 0 && tempDay <= 30)
{
if 30 days
}
}
else if(tempMonth == 2)
{
if(tempDay > 0 && tempDay <= 28)
{
if 28 days
}
}
else
{
if(tempDay > 0 && tempDay <= 31)
{
if 31 days
}
}
}
}
}
}

There are 4 things you want to check:
Is there 8 characters ? If not, then don't even bother checking anything else. It's not in the proper format.
Are the third and fifth characters '/'. If not, then you still don't have the proper format.
Check each pair for its valid values. A month has days between 1 and
31 at most, there are no more than 12 months and months range from 01
to 12. A year can be any combination of any 2 digits.
This should take care of the format, but if you want to make sure that the date is valid:
Check for valid number of days in each month (january 31, february
28-29...) and indeed check for those leap years.

This looks a lot like a project I am about to grade.... You should verify that it is Gregorian Calendar compliant if it is the project I am about to grade. 1/1/2012 is definitely valid though so what you may want to do and what I would hope you consider is creating a switch statement that examines for formats like 1/12/2012 and 10/2/2012 because these are valid. Then parse out the month day and year from these. Then verify that they are within the limit of the Gregorian calendar. If it is for a class which I would guess that it is, you should consider writing the verification as a separate function from the parsing function.
So first ask whether the date is too long if not, is it too short, if not which version is it, then pass the d m y to the verification function. This kind of modularity will simplify your code and reduce instructions.
something like
bool dateValidation(string shipDate)
{
string temp;
switch(shipDate.length())
{
case(10):
// do what your doing
verify(m,d,y);
break;
case(8):
//dealing with single digits
// verify 1 and 3 are '/' and the rest are numbers
verifiy(m,d,y);
break;
case(9):
//a little more heavy lifting here
// but its good thinking for a new programmer
verifiy(m,d,y);
break;
default:
//fail message
break;
}

Related

Input a date in 8 digit numerical form and display into English form

Below is the c++ problem i have to solve and i'm having some trouble from number 2)
1) Prompt the user to input a date in 8 digit numerical form(MMDDYYYY)
ex. 04221970
2) Display the date in English form
ex. 22nd April 1970
3) If the day the user entered is 01,21,31, add "st" after the day
4) Else if the day the user entered is 02,22, add "nd" after the day
5) Elae if the day user entered is 03,23, add "rd" after the day
6) Else add "th" after the day
All of the step are rather straightforward. But dates are always tricky, since there are many rules. But only a couple apply for parsing.
Define a struct to hold the parsed value and parse the input.
[EDIT] The value of using a struct, is that it can be useful to have an intermediate function that would return this reusable bit of binary data.
struct date_s
{
unsigned int day;
unsigned int month;
unsigned int year;
};
// parsing
date_s date = {};
if (strlen(input) != 8 || sscanf(input, "%2u%2u%4u", &date.month, &date.day, &date.year) != 3)
{
// handle error
}
Validating the year is rather easy, there is nothing to do, unless you want to restrict to a specific range. For example, since we're using the Gregorian calendar, you may want to restrict to years after 1582, inclusive.
Validating the month is also very straightforward, we'll validate that along with the number of days in a month, which is the most tricky part, because of Febuary.
unsigned int day_max = 0;
switch (date.month)
{
case 1: case 3: case 5; case 7: case 8: case 10: case 12:
day_max = 31;
break;
case 4: case 6: case 9: case 11:
day_max = 30;
break;
case 2:
if (date.year % 4 != 0)
day_max = 28;
else if (date.year % 100 != 0)
day_max = 29;
else if (date.year % 400 != 0)
day_max = 28;
else
day_max = 29;
break;
// else day_max stays 0, of course
}
if (date.day < 1 || day_max < date.day)
{
// error
}
After all the validating is done, all you have to do is print.
For the months you will need to define a table of strings for display.
const char* MONTH[12] = { "January", /* etc... */ };
Date suffix.
const char* SUFFIX[4] = { "st", "nd", "rd", "th" };
We now have all the data we need to print, and all within range, too.
const char* suffix = SUFFIX[std::min(date.day, 4) - 1];
printf("%d%s %s %d", date.day, suffix, MONTH[date.month - 1], date.year);
// or, for US format
printf("%s %d%s, %d", MONTH[date.month - 1], date.day, suffix, date.year);

C++ problems. I need help to a very simple and basic problems in C++

I am new in programming and I need a little help at a problem in C++ .
The problem is :
I need to read 3 numbers and to determinate if this numbers can be a date or not . I need to say "YES" if the numbers can be a date or "NOT" if they can`t be a date.
I've tried this :
#include <iostream>
using namespace std;
int main(){
unsigned int z, l, a;
cin >> z >> l >> a;
if((z<32 && l==1) || (z==29 && l==2 && a%4==0) ||
(z<29 && l==2 && a%4>0) ||(z<32 && l==3) ||
(z<31 && l==4) || (z<32 && l==5) || (z<31 && l==6) ||
(z<32 && l==7) || (z<31 && l==8) || (z<32 && l==9) ||
(z<31 && l==10) || (z<31 && l==1) || (z<31 && l==12)) cout << "YES";
else cout << "NO";
return 0;
}
Question:
Could you help me find the missed cases?
Note:
My teacher commented that "It is almost done but you miss some cases". I tried to find this cases 2 hours but I didn't succeed ...
Quick answer:
The missed cases probably are due to the missed leap years as your code currently doesn't use correct checking for that. The right check for leap year is at the end of the answer.
Firstly, try and figure out what are the cases on a piece of paper:
date is consisted of positive numbers
start date of Gregorian calendar (add comment to inform the user for interval of valid dates)
Formulate the format, e.g. it could be: dd/mm/yyyy or mm/dd/yyyy, i.e. 1.03.2015
which months have 30, 31, 28, 29 (in which years) days
leap years and February
Regarding the code:
1.Use meaningful variables that have names that explain their purpose, i.e.:
replace unsigned int z, l, a; with variables like: int month, day, year;
2.Create separate if- else if statements for each of the above cases and add comments to indicate them (it will make your code easy to read and understand).
// check if January has 31 days
if(z<32 && l==1){
// check if February has 29 days and it isn't a leap year
} else if (z==29 && l==2 && a%4==0){
} //...
Bugs in your code:
1.Your current check for leap year: a % 4 == 0 is not entirely correct. A proper check for leap year looks something like:
if year modulo 400 is 0 then
is_leap_year
else if year modulo 100 is 0 then
not_leap_year
else if year modulo 4 is 0 then
is_leap_year
else
not_leap_year
and in code:
if(((year % 4) == 0) && (((year % 100)!=0) || ((year % 400) == 0)){
//leap year
}
2.The check for November is not right: (z < 31 && l == 1). It should be:
(z < 31 && l == 11)

Search a string for a wildcard year C++

I'm looping through a text file, reading each paragraph into a string. I want to process any paragraphs that contain a year, but if no year is found then I want to continue looping through the file. When a year is found, I want to know the index where that year was found.
I'm trying to avoid any boost or regex code for simplicity. I also assume that the only years of interest will be in the 1900s and 2000s, for simplicity. I tried the following code, but the wildcard characters were not working for some reason. Is is because wildcard characters do not work for numbers?
string sParagraph = "Aramal et al. (2011), Title";
int iIndex;
if (sParagraph.find("19??")!=string::npos)
iIndex = sParagraph.find("19??");
else if (sParagraph.find("20??")!=string::npos)
iIndex = sParagraph.find("20??");
else
continue;
Without using regex or boost code you might be making your code more readable, but it will not be more simple.
A "simple" one-pass pseudo algorithm:
map<int, std::vector<int>> years;
String par = " ... "
//inefficient but didn't want to have to add more complicated code
//in the while loop. Just want to solution to be clear
int par_index = par.find_first_of("19");
if(par_index == string::npos)
par_index = par.find_first_of("20");
if(par_index == string::npos)
//skip //No years in this paragraph
while(par_index < par.size()) {
string year(par, par_index, 4);
int year = atoi(year.c_str()); //or use C++11 stoi
if(2100 < year && year >= 1900)
years.at(year).push_back(par_index);
par_index += 4;
}
This will create a map where the key is the year and the value is a vector of ints that represent the index that the year landed on.
EDIT: I just reread the question and noticed that this answer might be too irrelevant. Sorry if it is.
I was looking for something similar a couple days ago. My approach might be very (very very) inefficient: I looped through the entire string and used 'atoi()' to see whether each group of four characters was a year.
for (int i = 0; i < txt.length() - 3; i++)
{
string t = txt.substr(i, 4); //Take a group of four characters.
int year = atoi((char*)t.c_str());
if (year > 1800 && year < 3000)
{
break;
}
else year = 0;
}
At the end, 'year' is either zero or an actual year.
So of course you can do this. But it will not be simpler, it will be more complex.
Anyway, this is probably your best non-regex solution. It uses a string::iterator not a position:
string sParagraph = "Aramal et al. (2011), Title";
auto iIndex = adjacent_find(sParagraph.begin(), sParagraph.end(), [](char i, char j){return i == '1' && j == '9' || i == '2' && j == '0'; });
const auto end = next(sParagraph.end(), -3);
while (iIndex < end && (isdigit(static_cast<int>(*next(iIndex, 2))) == false || isdigit(static_cast<int>(*next(iIndex, 3))) == false)){
iIndex = adjacent_find(next(iIndex, 4), sParagraph.end(), [](char i, char j){return i == '1' && j == '9' || i == '2' && j == '0'; });
}
To use this you'll need to check if you have iterated to end:
if(iIndex < end){
continue;
}
Just for purpose of comparison, you can use a regex_search to determine if the year exists:
string sParagraph = "Aramal et al. (2011), Title";
smatch iIndex;
if (!regex_search(sParagraph, iIndex, regex("(?:19|20)\\d{2}"))){
continue;
}
An smatch contains far more information and just a position, but if you want the index of the start of the year you can do: iIndex.position()
A common pitfall for people who are not familiar with the features of C++11 is to say: "I don't understand how to use this stuff, it must be more complicated than what I already know." And then go back to what they already know. Don't make that mistake, use the regex_search.

Determining if a number is either a multiple of ten or within a particular set of ranges

I have a few loops that I need in my program. I can write out the pseudo code, but I'm not entirely sure how to write them logically.
I need -
if (num is a multiple of 10) { do this }
if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }
else { do this } //this part is for 1-10, 21-30, 41-50, 61-70, 81-90
This is for a snakes and ladders board game, if it makes any more sense for my question.
I imagine the first if statement I'll need to use modulus. Would if (num == 100%10) be correct?
The second one I have no idea. I can write it out like if (num > 10 && num is < 21 || etc.), but there has to be something smarter than that.
For the first one, to check if a number is a multiple of use:
if (num % 10 == 0) // It's divisible by 10
For the second one:
if(((num - 1) / 10) % 2 == 1 && num <= 100)
But that's rather dense, and you might be better off just listing the options explicitly.
Now that you've given a better idea of what you are doing, I'd write the second one as:
int getRow(int num) {
return (num - 1) / 10;
}
if (getRow(num) % 2 == 0) {
}
It's the same logic, but by using the function we get a clearer idea of what it means.
if (num is a multiple of 10) { do this }
if (num % 10 == 0) {
// Do something
}
if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }
The trick here is to look for some sort of commonality among the ranges. Of course, you can always use the "brute force" method:
if ((num > 10 && num <= 20) ||
(num > 30 && num <= 40) ||
(num > 50 && num <= 60) ||
(num > 70 && num <= 80) ||
(num > 90 && num <= 100)) {
// Do something
}
But you might notice that, if you subtract 1 from num, you'll have the ranges:
10-19, 30-39, 50-59, 70-79, 90-99
In other words, all two-digit numbers whose first digit is odd. Next, you need to come up with a formula that expresses this. You can get the first digit by dividing by 10, and you can test that it's odd by checking for a remainder of 1 when you divide by 2. Putting that all together:
if ((num > 0) && (num <= 100) && (((num - 1) / 10) % 2 == 1)) {
// Do something
}
Given the trade-off between longer but maintainable code and shorter "clever" code, I'd pick longer and clearer every time. At the very least, if you try to be clever, please, please include a comment that explains exactly what you're trying to accomplish.
It helps to assume the next developer to work on the code is armed and knows where you live. :-)
If you are using GCC or any compiler that supports case ranges you can do this, but your code will not be portable.
switch(num)
{
case 11 ... 20:
case 31 ... 40:
case 51 ... 60:
case 71 ... 80:
case 91 ... 100:
// Do something
break;
default:
// Do something else
break;
}
This is for future visitors more so than a beginner. For a more general, algorithm-like solution, you can take a list of starting and ending values and check if a passed value is within one of them:
template<typename It, typename Elem>
bool in_any_interval(It first, It last, const Elem &val) {
return std::any_of(first, last, [&val](const auto &p) {
return p.first <= val && val <= p.second;
});
}
For simplicity, I used a polymorphic lambda (C++14) instead of an explicit pair argument. This should also probably stick to using < and == to be consistent with the standard algorithms, but it works like this as long as Elem has <= defined for it. Anyway, it can be used like this:
std::pair<int, int> intervals[]{
{11, 20}, {31, 40}, {51, 60}, {71, 80}, {91, 100}
};
const int num = 15;
std::cout << in_any_interval(std::begin(intervals), std::end(intervals), num);
There's a live example here.
The first one is easy. You just need to apply the modulo operator to your num value:
if ( ( num % 10 ) == 0)
Since C++ is evaluating every number that is not 0 as true, you could also write:
if ( ! ( num % 10 ) ) // Does not have a residue when divided by 10
For the second one, I think this is cleaner to understand:
The pattern repeats every 20, so you can calculate modulo 20.
All elements you want will be in a row except the ones that are dividable by 20.
To get those too, just use num-1 or better num+19 to avoid dealing with negative numbers.
if ( ( ( num + 19 ) % 20 ) > 9 )
This is assuming the pattern repeats forever, so for 111-120 it would apply again, and so on. Otherwise you need to limit the numbers to 100:
if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )
With a couple of good comments in the code, it can be written quite concisely and readably.
// Check if it's a multiple of 10
if (num % 10 == 0) { ... }
// Check for whether tens digit is zero or even (1-10, 21-30, ...)
if ((num / 10) % 2 == 0) { ... }
else { ... }
You basically explained the answer yourself, but here's the code just in case.
if((x % 10) == 0) {
// Do this
}
if((x > 10 && x < 21) || (x > 30 && x < 41) || (x > 50 && x < 61) || (x > 70 && x < 81) || (x > 90 && x < 101)) {
// Do this
}
You might be overthinking this.
if (x % 10)
{
.. code for 1..9 ..
} else
{
.. code for 0, 10, 20 etc.
}
The first line if (x % 10) works because (a) a value that is a multiple of 10 calculates as '0', other numbers result in their remainer, (b) a value of 0 in an if is considered false, any other value is true.
Edit:
To toggle back-and-forth in twenties, use the same trick. This time, the pivotal number is 10:
if (((x-1)/10) & 1)
{
.. code for 10, 30, ..
} else
{
.. code for 20, 40, etc.
}
x/10 returns any number from 0 to 9 as 0, 10 to 19 as 1 and so on. Testing on even or odd -- the & 1 -- tells you if it's even or odd. Since your ranges are actually "11 to 20", subtract 1 before testing.
A plea for readability
While you already have some good answers, I would like to recommend a programming technique that will make your code more readable for some future reader - that can be you in six months, a colleague asked to perform a code review, your successor, ...
This is to wrap any "clever" statements into a function that shows exactly (with its name) what it is doing. While there is a miniscule impact on performance (from "function calling overhead") this is truly negligible in a game situation like this.
Along the way you can sanitize your inputs - for example, test for "illegal" values. Thus you might end up with code like this - see how much more readable it is? The "helper functions" can be hidden away somewhere (the don't need to be in the main module: it is clear from their name what they do):
#include <stdio.h>
enum {NO, YES, WINNER};
enum {OUT_OF_RANGE=-1, ODD, EVEN};
int notInRange(int square) {
return(square < 1 || square > 100)?YES:NO;
}
int isEndOfRow(int square) {
if (notInRange(square)) return OUT_OF_RANGE;
if (square == 100) return WINNER; // I am making this up...
return (square % 10 == 0)? YES:NO;
}
int rowType(unsigned int square) {
// return 1 if square is in odd row (going to the right)
// and 0 if square is in even row (going to the left)
if (notInRange(square)) return OUT_OF_RANGE; // trap this error
int rowNum = (square - 1) / 10;
return (rowNum % 2 == 0) ? ODD:EVEN; // return 0 (ODD) for 1-10, 21-30 etc.
// and 1 (EVEN) for 11-20, 31-40, ...
}
int main(void) {
int a = 12;
int rt;
rt = rowType(a); // this replaces your obscure if statement
// and here is how you handle the possible return values:
switch(rt) {
case ODD:
printf("It is an odd row\n");
break;
case EVEN:
printf("It is an even row\n");
break;
case OUT_OF_RANGE:
printf("It is out of range\n");
break;
default:
printf("Unexpected return value from rowType!\n");
}
if(isEndOfRow(10)==YES) printf("10 is at the end of a row\n");
if(isEndOfRow(100)==WINNER) printf("We have a winner!\n");
}
For the first one:
if (x % 10 == 0)
will apply to:
10, 20, 30, .. 100 .. 1000 ...
For the second one:
if (((x-1) / 10) % 2 == 1)
will apply for:
11-20, 31-40, 51-60, ..
We basically first do x-1 to get:
10-19, 30-39, 50-59, ..
Then we divide them by 10 to get:
1, 3, 5, ..
So we check if this result is odd.
As others have pointed out, making the conditions more concise won't speed up the compilation or the execution, and it doesn't necessarily help with readability either.
It can help in making your program more flexible, in case you decide later that you want a toddler's version of the game on a 6 x 6 board, or an advanced version (that you can play all night long) on a 40 x 50 board.
So I would code it as follows:
// What is the size of the game board?
#define ROWS 10
#define COLUMNS 10
// The numbers of the squares go from 1 (bottom-left) to (ROWS * COLUMNS)
// (top-left if ROWS is even, or top-right if ROWS is odd)
#define firstSquare 1
#define lastSquare (ROWS * COLUMNS)
// We haven't started until we roll the die and move onto the first square,
// so there is an imaginary 'square zero'
#define notStarted(num) (num == 0)
// and we only win when we land exactly on the last square
#define finished(num) (num == lastSquare)
#define overShot(num) (num > lastSquare)
// We will number our rows from 1 to ROWS, and our columns from 1 to COLUMNS
// (apologies to C fanatics who believe the world should be zero-based, which would
// have simplified these expressions)
#define getRow(num) (((num - 1) / COLUMNS) + 1)
#define getCol(num) (((num - 1) % COLUMNS) + 1)
// What direction are we moving in?
// On rows 1, 3, 5, etc. we go from left to right
#define isLeftToRightRow(num) ((getRow(num) % 2) == 1)
// On rows 2, 4, 6, etc. we go from right to left
#define isRightToLeftRow(num) ((getRow(num) % 2) == 0)
// Are we on the last square in the row?
#define isLastInRow(num) (getCol(num) == COLUMNS)
// And finally we can get onto the code
if (notStarted(mySquare))
{
// Some code for when we haven't got our piece on the board yet
}
else
{
if (isLastInRow(mySquare))
{
// Some code for when we're on the last square in a row
}
if (isRightToLeftRow(mySquare))
{
// Some code for when we're travelling from right to left
}
else
{
// Some code for when we're travelling from left to right
}
}
Yes, it's verbose, but it makes it clear exactly what's happening on the game board.
If I was developing this game to display on a phone or tablet, I'd make ROWS and COLUMNS variables instead of constants, so they can be set dynamically (at the start of a game) to match the screen size and orientation.
I'd also allow the screen orientation to be changed at any time, mid-game - all you need to do is switch the values of ROWS and COLUMNS, while leaving everything else (the current square number that each player is on, and the start/end squares of all the snakes and ladders) unchanged.
Then you 'just' have to draw the board nicely, and write code for your animations (I assume that was the purpose of your if statements) ...
You can try the following:
// Multiple of 10
if ((num % 10) == 0)
{
// Do something
}
else if (((num / 10) % 2) != 0)
{
// 11-20, 31-40, 51-60, 71-80, 91-100
}
else
{
// Other case
}
I know that this question has so many answers, but I will thrown mine here anyway...
Taken from Steve McConnell's Code Complete, 2nd Edition:
"Stair-Step Access Tables:
Yet another kind of table access is the stair-step method. This access method isn’t as direct as an index structure, but it doesn’t waste as much data space. The general idea of stair-step structures, illustrated in Figure 18-5, is that entries in a table are valid for ranges of data rather than for distinct data points.
Figure 18-5 The stair-step approach categorizes each entry by determining the level at which it hits a “staircase.” The “step” it hits determines its category.
For example, if you’re writing a grading program, the “B” entry range might be from 75 percent to 90 percent. Here’s a range of grades you might have to program someday:
To use the stair-step method, you put the upper end of each range into a table and then write a loop to check a score against the upper end of each range. When you find the point at which the score first exceeds the top of a range, you know what the grade is. With the stair-step technique, you have to be careful to handle the endpoints of the ranges properly. Here’s the code in Visual Basic that assigns grades to a group of students based on this example:
Although this is a simple example, you can easily generalize it to handle multiple students, multiple grading schemes (for example, different grades for different point levels on different assignments), and changes in the grading scheme."
Code Complete, 2nd Edition, pages 426 - 428 (Chapter 18).

An algorithm to get the next weekday set in a bitmask

I've got this small question - given a bitmask of weekdays (e.g., Sunday = 0x01, Monday = 0x02, Tuesday = 0x04, etc...) and today's day (in a form of Sunday = 1, Monday = 2, Tuesday = 3, etc...) - what's the most elegant way to find out the next day from today, that's set in the bitmask? By elegant I mean, is there a way to do this without if/switch/etc..., because I know the non-elegant way?
Edit I probably should've mentioned (to make this more clear) that the variable holding the bitmask can have several of the days set, so for example (roughly):
uDay = Sunday | Monday;
today = Tuesday;
I need to get "Sunday"
int getNextDay(int days_mask, int today) {
if (!days_mask) return -1; // no days set
days_mask |= days_mask << 7; // duplicate days into next week
mask = 1 << (today % 7); // keep track of the day
while (!(mask & days_mask)) {
mask <<= 1;
++today;
}
return today % 7;
}
So that's just one if at the beginning and while loop. How's that?
Edit: I just realized there was a degenerate case where if the use passes today>=14 (or greater than the highest bit set) the while loop becomes infinite. The (today % 7) on line 4 fixes this case.
And if I may grouse (light-heartedly) about the other version getting the checkmark, my version only have 2 modulus calls, while the checked solution will have a minimum of 1 and a maximum of 6 modulus calls.
Also, the comment about does the function return "today" if today is set is interesting. If the function should not return today unless today is the only day in the set would require that you pre-increment today on line 3 of my solution.
You don't need any extra variables at all. The simplest idea -- start with "tomorrow", look at successive days until you find a day in the mask -- is also the most elegant to implement. The trick to doing it nicely is to think of the days as Sunday=0, Monday=1 and so on (only inside this function). Then, "today" is actually t-1 (where t is the input to the function, so it goes from 1 to 7), and "tomorrow" is (t-1+1)%7 i.e t%7, etc.
This is simple and has been tested against litb's code exhaustively, just to be sure :-)
int getNextDay(int m, int t) {
if((m&127)==0) return t; //If no day is set, return today
t=t%7; //Start with tomorrow
while((m&(1<<t))==0) t = (t+1)%7; //Try successive days
return t+1; //Change back to Sunday=1, etc.
}
Edit: If you want "next" to mean "today or later", then the "t=t%7" line should be changed to t=t-1 or --t.
I understand your question this way:
// returns t (today) if no weekday is set in the mask.
int getNextDay(int m, int t) {
int i, idx;
for(i = 0, idx=t%7; i<7 && !((1<<idx)&m); i++, idx=(idx+1)%7)
/* body empty */ ;
return (i == 7) ? t : (idx + 1);
}
// getNextDay(8|2, 2) == 4, getNextDay(64, 2) == 7
// getNextDay(128, 2) == 2
By elegant I mean, is there a way to do this without if/switch/etc...
You bet! Whether that will mean 'elegant' in any usual sense, well:
static unsigned next_day_set (unsigned today, unsigned set) {
unsigned arev = bitreverse (highest_bit_set (bitreverse ((set << 7) | set)
& (bitreverse (today) - 1)));
return ((arev >> 7) | arev) & 0x7f;
}
That's assuming you have 'elegant' functions to reverse the bits in a word and find the leftmost bit set -- see Hacker's Delight. If you represented the weekday bits in the reverse order, it'd be simpler and actually even sort of elegant for real, assuming I didn't screw up:
enum {
Sunday = 1 << 6
Monday = 1 << 5
Tuesday = 1 << 4,
/* etc */
Saturday = 1 << 0
};
static unsigned next_day_set (unsigned today, unsigned set) {
unsigned a = highest_bit_set (((set << 7) | set) & ((today << 7) - 1));
return ((a >> 7) | a) & 0x7f;
}