Else if statement not executing , its supposed to console.log the last statement in this case - if-statement

// Do i have to place parathesis somewhere in the last else if to prioritize?
const dolphinScore = 88 + 91 + 110 / 3;
console.log(dolphinScore);
const koalaScore = 88 + 91 + 110 / 3;
console.log(koalaScore);
//88 + 91 + 110 / 3
const minScore = 100;
if (dolphinScore > koalaScore && minScore) {
console.log(`The dolhins win with a score ${dolphinScore}`)
} else if (koalaScore > dolphinScore && minScore) {
console.log(`The koalas win with a score of ${koalaScore}`)
} else if (dolphinScore == koalaScore && >= minScore) {
console.log("This is a draw , no one wins");
}
Expected the else if to execute but it isnt working go easy on me im re leaning the basics!
Else if statement not executing , its supposed to console.log the last statement in this case but its acting as if the (dolphinScore == koalaScore && >= minScore) isnt true?

I think that the problem lies in this line:
if (dolphinScore > koalaScore && minScore)
It should be:
if (dolphinScore > koalaScore && dolphinsScore > minScore)
The && operation must be between 2 boolean statement.

Changed the constant variables dophinsScore & koalaScore to just regular declarations and it executed heres my new code that works , could someone let me know if this is the proper way to solve this issue , thank you and happy programming!
let dolphinScore = 88 + 91 + 110 / 3;
console.log(dolphinScore);
let koalaScore = 88 + 91 + 110 / 3;
console.log(koalaScore);
//88 + 91 + 110 / 3
const minScore = 100;
if (dolphinScore > koalaScore && minScore) {
console.log(`The dolhins win with a score ${dolphinScore}`)
} else if (koalaScore > dolphinScore && minScore) {
console.log(`The koalas win with a score of ${koalaScore}`)
} else if (dolphinScore == koalaScore || dolphinScore, koalaScore = minScore) {
console.log("This is a draw , no one wins");
}

Related

Math: How to optimize this if so it looks cleaner and faster?

This solution looks ugly. I've tried to simplify using a vector and cycling a vector but would it be faster? I tried making up a formula to retrieve these numbers but I'm terrible at math!
if (SkillValue > 115 && SkillValue <= 135)
{
return 100 / 2;
}
else if (SkillValue > 135 && SkillValue <= 160)
{
return 100 / 3;
}
else if (SkillValue > 160 && SkillValue <= 190)
{
return 100 / 4;
}
else if (SkillValue > 190 && SkillValue <= 215)
{
return 100 / 5;
}
else if (SkillValue > 215 && SkillValue <= 295)
{
return 100 / 6;
}
else if (SkillValue > 295 && SkillValue <= 315)
{
return 100 / 9;
}
else if (SkillValue > 315 && SkillValue <= 355)
{
return 100 / 10;
}
else if (SkillValue > 355 && SkillValue <= 425)
{
return 100 / 11;
}
else if (SkillValue > 425 && SkillValue < 450)
{
return 100 / 12;
}
return 100;
}
There doesn't appear to be any pattern to the bounds for each if condition, or at least any pattern that would let you write this as a closed form check.
However, you are currently checking all the if conditions, which is O(n) where n is the number of conditions. You can do this in O(log(n)) by using std::lower_bound on a range to find the value of the denominator, like this:
std::array bounds { 115, 135, 160, 190, ... };
std::array dens {1, 2, 3, 4, ... , 1}; // extra 1 at the end to account for the
// case that none of the bounds match
auto it = std::lower_bound(std::begin(bounds), std::end(bounds), SkillValue);
return 100 / dens[std::distance(std::begin(bounds), it)];
Right off the bat, you are repeating logic in each conditional that can be refactored out of the previous conditionals by switching to the following form:
if (SkillValue <= 115) {
return 100/1;
} else if (SkillValue <= 135) {// the 'else' explicitly means that it is already NOT <= 115, aka IS > 115, so no need to repeat with a '&&'
return 100/2;
} else if (SkillValue <= 160) {
return 100/3;
} else if (SkillValue <= 190) {
return 100/4;
}//... and so on
It's hard to find an equation to compute your result because your ranges are not equal in size, and the divisor jumps at 295.
To make a more compact version, here's a way:
#include <algorithm>
#include <iterator>
// 296 repeats to compensate for the jump in your divisor
constexpr int ranges[] = {0, 115, 136, 161, 191, 216, 296, 296, 296, 316, 356, 426, 456};
int compute(int SkillValue) {
if (SkillValue <= 115 or SkillValue >= 450) {
return 100;
}
auto elt = std::upper_bound(std::begin(ranges), std::end(ranges), SkillValue);
return 100 / (elt == std::end(ranges) ? 1 : elt - std::begin(ranges));
}
This computes the same output as your original function, but I can't actually say I like it any better.
Using a map, it's a little easier to read:
#include <map>
const std::map<int,int> ranges {
{115, 1},
{135, 2},
{160, 3},
{190, 4},
{215, 5},
{295, 6},
{315, 9},
{355, 10},
{425, 11},
{450, 12}
};
int compute(int SkillValue) {
if (SkillValue <= 115 or SkillValue >= 450) return 100;
auto elt = ranges.upper_bound(SkillValue-1);
return 100 / (elt == std::end(ranges) ? 1 : elt->second);
}

Please explain this snippet of code (return statement)

I'm having trouble deciphering this bit of code. I've encountered a return statement as complicated as this, so can someone break it down for me? (This code was from a problem in which I had to differentiate between a leap year and a non-leap year). Thanks!
return ((year % 4) || (!(year % 100) && ((year+300) % 400))) ? 28 : 29;
It's just a conditional expression, condition ? true_value : false_value.
It gets clearer if you separate out the condition:
bool not_leap_year = (year % 4) || (!(year % 100) && ((year+300) % 400));
return not_leap_year ? 28 : 29;
It's more common to compute the negation of the condition though, as the rules for when there is a leap year are better known than the rules for when there isn't (so there's less chance of bugs).
bool leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
return leap_year ? 29 : 28;
((year % 4) || (!(year % 100) && ((year+300) % 400))) ? 28 : 29;
This is the ternary operator ? with a relatively complex boolean expression. You could achieve the same with an if expression:
if ( (year % 4) // year not dividable by 4
or
(
not (year % 100) // year dividable by 100
and
((year+300) % 400))) // year + 300 not dividable by 400
{
return 28;
}
else
{
return 29;
}
One can make that a bit more readable using a helper function:
bool dividableBy(unsigned value, unsigned divisor) {
return value % divisor == 0;
}
//...
if ((not dividableBy(year, 4)) or
(dividableBy(year, 100) and
(not dividableBy(year+300, 400)))) {
return 28;
}
else {
return 29;
}

Doctirine 2 Case Statement

I use Doctirine 2 and zf2. How can i convert this sql query to dql. (Doctirine Query Language)
My product entity is here "Application\Entity\Product" I 've tried it but it doesn't work..
Thanks for your help.
SELECT price_range, count(*) AS num
FROM
(SELECT CASE WHEN price >= 0 AND price <= 10 THEN '0-10'
WHEN price >= 10 AND price <= 20 THEN '10-20'
WHEN price >= 20 AND price <= 30 THEN '30-40'
WHEN price >= 30 AND price <= 40 THEN '30-40'
WHEN price >= 40 AND price <= 50 THEN '40-50'
WHEN price >= 50 AND price <= 60 THEN '50-60'
WHEN price >= 60 AND price <= 70 THEN '60-70'
WHEN price >= 70 AND price <= 80 THEN '70-80'
WHEN price >= 80 AND price <= 90 THEN '90-100'
WHEN price >= 100 AND price <= 110 THEN '100-110'
ELSE 'over 1000'
END as price_range
FROM product
WHERE 1
) AS price_summaries
GROUP BY price_range
Well, unfortunately you can't. Doctrine doesn't support CASE. And looking at your problem, I'm also unable to find an adequate other solution with DQL.
You can however use a native query. Native queries are embedded raw SQL queries, basically an extension of PDO.
Native queries are of course generally discouraged, as they have two disadvantages:
You must do the hydration into Doctrine entities yourself, using ResultSetMapping (if you want the result of the query to contain ready-made entities instead of plain arrays/objects).
Native queries undermine the whole point of using a DBAL: you loose portability. (But, to be honest, most projects don't just switch their RDBMS, so it's a rather theoretical concern).
But if you need to have the above query executed, use a native query in this single case.
Doctirine support case statement.
This works
SELECT CASE WHEN (p.price >= 0 AND p.price <= 10) THEN '0-10'
WHEN (p.price >= 10 AND p.price <= 20) THEN '10-20'
WHEN (p.price >= 20 AND p.price <= 30) THEN '30-40'
WHEN (p.price >= 30 AND p.price <= 40) THEN '30-40'
WHEN (p.price >= 40 AND p.price <= 50) THEN '40-50'
WHEN (p.price >= 50 AND p.price <= 60) THEN '50-60'
WHEN (p.price >= 60 AND p.price <= 70) THEN '60-70'
WHEN (p.price >= 70 AND p.price <= 80) THEN '70-80'
WHEN (p.price >= 80 AND p.price <= 90) THEN '90-100'
WHEN (p.price >= 100 AND p.price <= 110) THEN '100-110'
ELSE 'over 1000'
END as price_range
FROM \Application\Entity\Product p
But this doesn't work, i think i should try native query
SELECT price_range, count(*) AS num
FROM
(SELECT CASE WHEN (p.price >= 0 AND p.price <= 10) THEN '0-10'
WHEN (p.price >= 10 AND p.price <= 20) THEN '10-20'
WHEN (p.price >= 20 AND p.price <= 30) THEN '30-40'
WHEN (p.price >= 30 AND p.price <= 40) THEN '30-40'
WHEN (p.price >= 40 AND p.price <= 50) THEN '40-50'
WHEN (p.price >= 50 AND p.price <= 60) THEN '50-60'
WHEN (p.price >= 60 AND p.price <= 70) THEN '60-70'
WHEN (p.price >= 70 AND p.price <= 80) THEN '70-80'
WHEN (p.price >= 80 AND p.price <= 90) THEN '90-100'
WHEN (p.price >= 100 AND p.price <= 110) THEN '100-110'
ELSE 'over 1000'
END as price_range
FROM \Application\Entity\Product p
) AS price_summaries
GROUP BY price_range

Nested Switch statements

Currently I am trying to create a program which will automatically generate a completed Sudoku board from scratch although the same functions could with minor alteration be used to solve a partially filled Sudoku board. Any way the issue is that when loading a new number into the board you obviously have to check whether the number already exists in the same column or row, but also in the same 3x3 square that it is being loaded into. Using nested switch statements for the part of the program where you must check the number against the numbers in the same 3x3 square and despite that the break statements all appear to be in the correct place. The compliler is saying of the first number of the second case statement that is part of the nested switch statement that : "Error: case label value has already appeared in this switch" even though the number hasn't and the question is why?
Here is the code:
bool SudokuClass::checkPresentGrid(int &temporary, int row, int column)
{
bool indicator;
switch (row)
{
case 0 || 3 || 6: //If the number is being loaded into row 0,3 or 6
switch (column)
{
case 0 || 3 || 6: //Check all other spaces in the same 3x3 grid
if (temporary == (completeSudoku[row + 1][column + 1] || completeSudoku[row + 1][column + 2] || completeSudoku[row + 2][column + 1] || completeSudoku[row + 2][column + 2]))
{
indicator = true;
}
break;
case 1 || 4 || 7:
if (temporary == (completeSudoku[row + 1][column - 1] || completeSudoku[row + 1][column + 1] || completeSudoku[row + 2][column - 1] || completeSudoku[row + 2][column + 1]))
{
indicator = true;
}
break;
case 2 || 5 || 8:
if (temporary == (completeSudoku[row + 1][column - 2] || completeSudoku[row + 1][column - 1] || completeSudoku[row + 2][column - 2] || completeSudoku[row + 2][column - 1]))
{
indicator = true;
}
break;
}
break;
case 1 || 4 || 7: //If the number is being loaded into row 1, 4 or 7
switch (column)
{
case 0 || 3 || 6: //Check all other spaces in the same 3x3 grid
if (temporary == (completeSudoku[row - 1][column + 1] || completeSudoku[row - 1][column + 2] || completeSudoku[row + 1][column + 1] || completeSudoku[row + 1][column + 2]))
{
indicator = true;
}
break;
case 1 || 4 || 7:
if (temporary == (completeSudoku[row - 1][column - 1] || completeSudoku[row - 1][column + 1] || completeSudoku[row + 1][column - 1] || completeSudoku[row + 1][column + 1]))
{
indicator = true;
}
break;
case 2 || 5 || 8:
if (temporary == (completeSudoku[row - 1][column - 2] || completeSudoku[row - 1][column - 1] || completeSudoku[row + 1][column - 2] || completeSudoku[row + 1][column - 1]))
{
indicator = true;
}
break;
}
break;
case 2 || 5 || 8: //If the number is being loaded into row 2, 5 or 8
switch (column)
{
case 0 || 3 || 6: //Check all other spaces in the same 3x3 grid
if (temporary == (completeSudoku[row - 2][column + 1] || completeSudoku[row - 2][column + 2] || completeSudoku[row - 1][column + 1] || completeSudoku[row - 1][column + 2]))
{
indicator = true;
}
break;
case 1 || 4 || 7:
if (temporary == (completeSudoku[row - 2][column - 1] || completeSudoku[row - 2][column + 1] || completeSudoku[row - 1][column - 1] || completeSudoku[row - 1][column + 1]))
{
indicator = true;
}
break;
case 2 || 5 || 8:
if (temporary == (completeSudoku[row - 2][column - 2] || completeSudoku[row - 2][column - 1] || completeSudoku[row - 1][column - 2] || completeSudoku[row - 1][column - 1]))
{
indicator = true;
}
break;
}
break;
}
return indicator;
}
Change
case 0 || 3 || 6: //If the number is being loaded into row 0,3 or 6
to
case 0:
case 3:
case 6: //If the number is being loaded into row 0,3 or 6
... and so on, with your other case statements.
Your code case 0 || 3 || 6
is evaluated as case (0 || 3 || 6)
which becomes case (false || true || true)
which becomes case (true), which wasn't what you intended.
case statements MUST be values. You're trying to compare against the results of EXPRESSIONS.
e.g. given this code:
switch($foo) {
case $bar || $baz:
...
}
rewritten as an conventional if() it will be executed exactly the same as:
$temp = $bar || $baz; // boolean OR operation, $temp becomes true/false
if ($foo == $temp) {
...
You're trying to treat it as:
if (($temp == $bar) || ($temp == $baz))
which it definitely isn't.
If you want to compare multiple values and have each of them execute the same bit of code, then use the switch fall-through behavior:
switch($foo) {
case $bar:
case $baz:
.... do something
break;

C/C++: how to get integer unix timestamp of build time (not string)

I'm trying to achieve pretty trivial thing: I need to store integer 32-bit unix timestamp of the build time, but all the macro I've found (__DATE__, __TIME__, __TIMESTAMP__) expand to string, not integer.
It seems, we just haven't it (which is pretty strange to me). I really want to have integer, not string.
What are the best practices to get it?
UPD:
As a side note: I do embedded stuff, so I have insufficient resources (say, 128 KB of flash memory), therefore it's really bad idea to parse string.
Why do I need that: I just need to have unique version number of each beta build. Firstly, the hex file will be named like my-firmware-v2-33-BETA-1397315745.hex, and secondly, when I need to show current version on device's screen, I might want to echo it in various format.
So, I had a little fun this evening and created a header file with macros to generate a UNIX timestamp, without any external program or special compiler feature! Just include the header and use the __TIME_UNIX__ macro.
Actually the code is pretty simple:
Number characters in the strings are converted to numbers with str[i]-'0' as loreb suggested and weighed according to their position.
The month string is processed similiar to chux answer; the chars are checked individually and evaluated as a group with the ? : operator.
Counting the days of the last months is done with commutative ? : expressions.
Leap year calculation is simple as within the UNIX time frame one leap day is inserted every 4 years
Finally all individual values are weighed with the respective amount of seconds to get the UNIX time. Note that SEC_PER_DAY must be subracted once, as JAN 01 1970, 00:00:00 must be 0.
The code has been tested in ATMEL Studio 7 (Visual Studio 2015) with the default compiler and settings (avr-gcc, -O1 optimisation) and the result has been confirmed by checking the generated .lss file.
Copy & paste the code below into a header file and include it wherever you need it. Enjoy!
/*
* compile_time.h
*
* Created: 30.05.2017 20:57:58
* Author: Dennis (instructable.com/member/nqtronix)
*
* This code provides the macro __TIME_UNIX__ which returns the current time in UNIX format. It can
* be used to identify a version of code on an embedded device, to initialize its RTC and much more.
* Along that several more constants for seconds, minutes, etc. are provided
*
* The macro is based on __TIME__ and __DATE__, which are assumed to be formatted "HH:MM:SS" and
* "MMM DD YYYY", respectively. The actual value can be calculated by the C compiler at compile time
* as all inputs are literals. MAKE SURE TO ENABLE OPTIMISATION!
*/
#ifndef COMPILE_TIME_H_
#define COMPILE_TIME_H_
// extracts 1..4 characters from a string and interprets it as a decimal value
#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0)
#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
// Some definitions for calculation
#define SEC_PER_MIN 60UL
#define SEC_PER_HOUR 3600UL
#define SEC_PER_DAY 86400UL
#define SEC_PER_YEAR (SEC_PER_DAY*365)
#define UNIX_START_YEAR 1970UL
// Custom "glue logic" to convert the month name to a usable number
#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
#define GET_MONTH2DAYS(month) ((month == 1 ? 0 : 31 + \
(month == 2 ? 0 : 28 + \
(month == 3 ? 0 : 31 + \
(month == 4 ? 0 : 30 + \
(month == 5 ? 0 : 31 + \
(month == 6 ? 0 : 30 + \
(month == 7 ? 0 : 31 + \
(month == 8 ? 0 : 31 + \
(month == 9 ? 0 : 30 + \
(month == 10 ? 0 : 31 + \
(month == 11 ? 0 : 30)))))))))))) \
#define GET_LEAP_DAYS ((__TIME_YEARS__-1968)/4 - (__TIME_MONTH__ <=2 ? 1 : 0))
#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6)
#define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3)
#define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0)
#define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4)
#define __TIME_MONTH__ GET_MONTH(__DATE__, 0)
#define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7)
#define __TIME_UNIX__ ((__TIME_YEARS__-UNIX_START_YEAR)*SEC_PER_YEAR+ \
GET_LEAP_DAYS*SEC_PER_DAY+ \
GET_MONTH2DAYS(__TIME_MONTH__)*SEC_PER_DAY+ \
__TIME_DAYS__*SEC_PER_DAY-SEC_PER_DAY+ \
__TIME_HOURS__*SEC_PER_HOUR+ \
__TIME_MINUTES__*SEC_PER_MIN+ \
__TIME_SECONDS__)
#endif /* COMPILE_TIME_H_ */
Edit:
The initial version does not take care of 100 and 400 modulo years effects on the number of days in February. This should not be a problem between 2001 and 2101, but here is a more general macro:
/*
*
* Created: 29.03.2018
*
* Authors:
*
* Assembled from the code released on Stackoverflow by:
* Dennis (instructable.com/member/nqtronix) | https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
* and
* Alexis Wilke | https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
*
* Assembled by Jean Rabault
*
* UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro.
* This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
*
* Careful: __TIME__ is the local time of the computer, NOT the UTC time in general!
*
*/
#ifndef COMPILE_TIME_H_
#define COMPILE_TIME_H_
// Some definitions for calculation
#define SEC_PER_MIN 60UL
#define SEC_PER_HOUR 3600UL
#define SEC_PER_DAY 86400UL
#define SEC_PER_YEAR (SEC_PER_DAY*365)
// extracts 1..4 characters from a string and interprets it as a decimal value
#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0)
#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
// Custom "glue logic" to convert the month name to a usable number
#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
// extract the information from the time string given by __TIME__ and __DATE__
#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6)
#define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3)
#define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0)
#define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4)
#define __TIME_MONTH__ GET_MONTH(__DATE__, 0)
#define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7)
// Days in February
#define _UNIX_TIMESTAMP_FDAY(year) \
(((year) % 400) == 0UL ? 29UL : \
(((year) % 100) == 0UL ? 28UL : \
(((year) % 4) == 0UL ? 29UL : \
28UL)))
// Days in the year
#define _UNIX_TIMESTAMP_YDAY(year, month, day) \
( \
/* January */ day \
/* February */ + (month >= 2 ? 31UL : 0UL) \
/* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
/* April */ + (month >= 4 ? 31UL : 0UL) \
/* May */ + (month >= 5 ? 30UL : 0UL) \
/* June */ + (month >= 6 ? 31UL : 0UL) \
/* July */ + (month >= 7 ? 30UL : 0UL) \
/* August */ + (month >= 8 ? 31UL : 0UL) \
/* September */+ (month >= 9 ? 31UL : 0UL) \
/* October */ + (month >= 10 ? 30UL : 0UL) \
/* November */ + (month >= 11 ? 31UL : 0UL) \
/* December */ + (month >= 12 ? 30UL : 0UL) \
)
// get the UNIX timestamp from a digits representation
#define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
( /* time */ second \
+ minute * SEC_PER_MIN \
+ hour * SEC_PER_HOUR \
+ /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
+ /* year */ (year - 1970UL) * SEC_PER_YEAR \
+ ((year - 1969UL) / 4UL) * SEC_PER_DAY \
- ((year - 1901UL) / 100UL) * SEC_PER_DAY \
+ ((year - 1601UL) / 400UL) * SEC_PER_DAY \
)
// the UNIX timestamp
#define UNIX_TIMESTAMP (_UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__))
#endif
You can generate a timestamp.h file on every build as a pre-build step and include that file in Your source codes. I don't know what build tools are You using (embedded world is very broad), bud every build tool I have seen so far allowed user to define custom pre-build and post-build steps (Freescale CodeWarrior, AVR studio, MSVS...).
For example in AVR studio on Windows I used this pre-build step (note that the $(SolutionDir) is specific for AVR stuio, which is based on MSVS, You may substitute with any filesystem path You need):
FOR /F %%A IN ('C:\cygwin\bin\date +%s') DO SET BUILD_TIMESTAMP=%%A
echo #define BUILD_TIME %BUILD_TIMESTAMP% > "$(SolutionDir)timestamp.h"
And in one of the project's C files I normally include this generated file (Your path to that file may differ...):
#include "../timestamp.h"
The generated file looks like this:
#define BUILD_TIME 1397317498
So when I click "build project", the studio first runs my commands, generates new timestamp.h and then uses it as an include in any other C files.
Note that the example above uses Cygwin (C:\cygwin\bin\date +%s) to get the timestamp. If You don't want to use Cygwin, You will have to find some other way for Windows to generate a timestamp for You. You may write Your own command-line utility (it should be about 10 lines of code in C :-) or search the Internet for some other way.
Why not to define it on command line?
gcc -DCOMPILE_TIME=`date '+%s'` mysources.c
/**
* #brief Macros to get integer build timestamp:
* __DATE_TIME_Y2K__ seconds since 2000-01-01,00:00:00
* __DATE_TIME_UNIX__ seconds since 1970-01-01 00:00:00
*
* 01234567890 01234567
* __DATE__ "Jul 27 2019" __TIME__ "12:34:56"
*/
#ifndef __DATE_TIME_H__
#define __DATE_TIME_H__
// For testing
//#define __DATE__ ("Jan 01 2000")
//#define __TIME__ ("00:00:00")
#define Y2K_UNIX_EPOCH_DIFF 946684800U
#define YEARS ((__DATE__[10] - '0' + (__DATE__[9] - '0') * 10))
#define DAY_OF_MONTH ((__DATE__[5] - '0') \
+ (((__DATE__[4] > '0')? __DATE__[4] - '0': 0) * 10) - 1)
#define DAY_OF_YEAR ((DAY_OF_MONTH) + \
( /* Jan */ (__DATE__[0] == 'J' && __DATE__[1] == 'a')? 0: \
/* Feb */ (__DATE__[0] == 'F' )? 31: \
/* Mar */ (__DATE__[0] == 'M' && __DATE__[2] == 'r')? 59: \
/* Apr */ (__DATE__[0] == 'A' && __DATE__[1] == 'p')? 90: \
/* May */ (__DATE__[0] == 'M' )? 120: \
/* Jun */ (__DATE__[0] == 'J' && __DATE__[2] == 'n')? 151: \
/* Jul */ (__DATE__[0] == 'J' )? 181: \
/* Aug */ (__DATE__[0] == 'A' )? 212: \
/* Sep */ (__DATE__[0] == 'S' )? 243: \
/* Oct */ (__DATE__[0] == 'O' )? 273: \
/* Nov */ (__DATE__[0] == 'N' )? 304: \
/* Dec */ 334 ))
#define LEAP_DAYS (YEARS / 4 + ((YEARS % 4 == 0 && DAY_OF_YEAR > 58)? 1 : 0) )
#define __DATE_TIME_Y2K__ ( (YEARS * 365 + LEAP_DAYS + DAY_OF_YEAR ) * 86400 \
+ ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0') * 3600 \
+ ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0') * 60 \
+ ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0') )
#define __DATE_TIME_UNIX__ ( __DATE_TIME_Y2K__ + Y2K_UNIX_EPOCH_DIFF )
#endif /* __DATE_TIME_H__ */
This is just a tighter, lighter version developed from #nqtronix 's version above. Enjoy!
Note: This macro ignores century, and so only works between 2000-01-01,00:00:00 and 2099-12-31,23:59:59.
Look at the following atrocity:
#include <stdio.h>
#define dec(ch) ((ch)-'0')
#define t(index, multiplier) (dec(__TIME__[index]) * (multiplier))
/* only minutes and seconds - you get the idea */
#define mmss() (t(3,600) + t(4,60) + t(6,10) + t(7,1))
int main()
{
/*
int i;
printf("time = %s\n", __TIME__);
for(i=0; __TIME__[i]; i++)
printf("t(%d) = %d\n", i, t(i,1));
*/
printf("mmss = %d\n", mmss());
return 0;
}
On my computer gcc -O is able to optimize it to a constant value; to get a full time_t, you'll need a cousin macro for __DATE__ and look at the generated assembly.
If anyone asks, I didn't write this answer ;)
Edit: just to be clear, you should probably follow Roman Hocke's answer and write a short C program to generate the value for you (of course if you're cross compiling you should be a bit careful...)
Edit:
As per #Lưu Vĩnh Phúc comment, it seems the key idea needs explaining: All calculation is done as compile time. See far below the OP codes generated.
Rather than generate time_t, the below generates struct tm in the timezone of the compiler. If needed, a call to mktime() will then return time_t.
time_t CompileTime = mktime(CompileTimeTM());
printf("%lld\n", (long long) CompileTime);
In other applications, instead of returning a struct tm, each of the fields assignments simple print the value to show the version.
else if ((d[3]=='M') && (d[4]=='a') && (d[5]=='y')) Print2Dig(5);
The below lengthy code generates few instructions in a PIC compiler as it optimizes out a lot. A similar approach could use __TIMESTAMP__.
// Dummy: used to detect a bad date parsing in Send_ID()
extern void BadDateM(void);
struct tm *CompileTimeTM(void) {
static const char d[10] = __DATE__;
static const char t[10] = __TIME__;
static struct tm ct;
ct.tm_year = (d[7]-'0')*10 + (d[8]-'0') + 2000 - 1900;
#IGNORE_WARNINGS 204
if (0) ;
else if ((d[3]=='J') && (d[4]=='a') && (d[5]=='n')) ct.tm_mon = 1-1;
else if ((d[3]=='F') && (d[4]=='e') && (d[5]=='b')) ct.tm_mon = 2-1;
else if ((d[3]=='M') && (d[4]=='a') && (d[5]=='r')) ct.tm_mon = 3-1;
else if ((d[3]=='A') && (d[4]=='p') && (d[5]=='r')) ct.tm_mon = 4-1;
else if ((d[3]=='M') && (d[4]=='a') && (d[5]=='y')) ct.tm_mon = 5-1;
else if ((d[3]=='J') && (d[4]=='u') && (d[5]=='n')) ct.tm_mon = 6-1;
else if ((d[3]=='J') && (d[4]=='u') && (d[5]=='l')) ct.tm_mon = 7-1;
else if ((d[3]=='A') && (d[4]=='u') && (d[5]=='g')) ct.tm_mon = 8-1;
else if ((d[3]=='S') && (d[4]=='e') && (d[5]=='p')) ct.tm_mon = 9-1;
else if ((d[3]=='O') && (d[4]=='c') && (d[5]=='t')) ct.tm_mon = 10-1;
else if ((d[3]=='N') && (d[4]=='o') && (d[5]=='v')) ct.tm_mon = 11-1;
else if ((d[3]=='D') && (d[4]=='e') && (d[5]=='c')) ct.tm_mon = 12-1;
else BadDateM(); // compile this if no match above, and thus fail link.
#IGNORE_WARNINGS NONE
ct.tm_mday = (d[0]-'0')*10 + (d[1]-'0');
ct.tm_hour = (t[0]-'0')*10 + (t[1]-'0');
ct.tm_min = (t[3]-'0')*10 + (t[4]-'0');
ct.tm_sec = (t[6]-'0')*10 + (t[7]-'0');
ct.tm_isdst = -1; // information is not available.
// ct.tm_yday = 0;
// ct.tm_wday = 0;
return &ct;
}
Listing
struct tm *CompileTimeTM(void) {
static const char d[10] = __DATE__;
static const char t[10] = __TIME__;
static struct tm ct;
ct.tm_year = (d[7]-'0')*10 + (d[8]-'0') + 2000 - 1900;
0F78 200724 MOV #72,W4 : W4 = 72
0F7A 8864D4 MOV W4,C9A : C9A = W4
#IGNORE_WARNINGS 204
if (0) ;
else if ((d[3]=='J') && (d[4]=='a') && (d[5]=='n')) ct.tm_mon = 1-1;
else if ((d[3]=='F') && (d[4]=='e') && (d[5]=='b')) ct.tm_mon = 2-1;
else if ((d[3]=='M') && (d[4]=='a') && (d[5]=='r')) ct.tm_mon = 3-1;
else if ((d[3]=='A') && (d[4]=='p') && (d[5]=='r')) ct.tm_mon = 4-1;
0F7C 200034 MOV #3,W4 : W4 = 3
0F7E 8864C4 MOV W4,C98 : C98 = W4
else if ((d[3]=='M') && (d[4]=='a') && (d[5]=='y')) ct.tm_mon = 5-1;
else if ((d[3]=='J') && (d[4]=='u') && (d[5]=='n')) ct.tm_mon = 6-1;
else if ((d[3]=='J') && (d[4]=='u') && (d[5]=='l')) ct.tm_mon = 7-1;
else if ((d[3]=='A') && (d[4]=='u') && (d[5]=='g')) ct.tm_mon = 8-1;
else if ((d[3]=='S') && (d[4]=='e') && (d[5]=='p')) ct.tm_mon = 9-1;
else if ((d[3]=='O') && (d[4]=='c') && (d[5]=='t')) ct.tm_mon = 10-1;
else if ((d[3]=='N') && (d[4]=='o') && (d[5]=='v')) ct.tm_mon = 11-1;
else if ((d[3]=='D') && (d[4]=='e') && (d[5]=='c')) ct.tm_mon = 12-1;
else BadDateM(); // compile this if no match above, and thus fail link.
#IGNORE_WARNINGS NONE
ct.tm_mday = (d[0]-'0')*10 + (d[1]-'0');
0F80 2000E4 MOV #E,W4 : W4 = E
0F82 8864B4 MOV W4,C96 : C96 = W4
ct.tm_hour = (t[0]-'0')*10 + (t[1]-'0');
0F84 2000B4 MOV #B,W4 : W4 = B
0F86 8864A4 MOV W4,C94 : C94 = W4
ct.tm_min = (t[3]-'0')*10 + (t[4]-'0');
0F88 200354 MOV #35,W4 : W4 = 35
0F8A 886494 MOV W4,C92 : C92 = W4
ct.tm_sec = (t[6]-'0')*10 + (t[7]-'0');
0F8C 2000D4 MOV #D,W4 : W4 = D
0F8E 886484 MOV W4,C90 : C90 = W4
I found I had to add a special check if the day of month was less than 10 - otherwise it returns a negative number
// special case to handle __DATE__ not inserting leading zero on day of month
// if Day of month is less than 10 - it inserts a blank character
// this results in a negative number for tm_mday
if(d[4] == ' ')
{
ct.tm_mday = d[5]-'0';
}
else
{
ct.tm_mday = (d[4]-'0')*10 + (d[5]-'0');
}
Since you're using C++, I think you could use constexpr functions to parse the __DATE__ __TIME__ strings on compilation.
As:
#include <stdint.h>
struct time_custom_t {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
};
#define __SECONDS_FROM_1970_TO_2000 \
946684800 ///< Unixtime for 2000-01-01 00:00:00, useful for initialization
constexpr uint16_t conv2d(const char *p)
{
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
constexpr uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
const uint8_t daysInMonth[] = {31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30};
if (y >= 2000U)
y -= 2000U;
uint16_t days = d;
for (uint8_t i = 1; i < m; ++i)
days += daysInMonth[i - 1];
if (m > 2 && y % 4 == 0)
++days;
return days + 365 * y + (y + 3) / 4 - 1;
}
constexpr uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
return ((days * 24UL + h) * 60 + m) * 60 + s;
}
constexpr time_custom_t getBuildTime(const char *date, const char *time)
{
time_custom_t dt{};
dt.year = conv2d(date + 9);
dt.day = conv2d(date + 4);
dt.hour = conv2d(time);
dt.minute = conv2d(time + 3);
dt.second = conv2d(time + 6);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date[0])
{
case 'J': dt.month = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7); break;
case 'F': dt.month = 2; break;
case 'A': dt.month = date[2] == 'r' ? 4 : 8; break;
case 'M': dt.month = date[2] == 'r' ? 3 : 5; break;
case 'S': dt.month = 9; break;
case 'O': dt.month = 10; break;
case 'N': dt.month = 11; break;
case 'D': dt.month = 12; break;
}
return dt;
}
constexpr uint32_t getBuildTimeAsUnixTime(const char *date, const char *time)
{
time_custom_t dt = getBuildTime (date, time);
uint32_t unixTime = 0;
unixTime = time2ulong(date2days(dt.year, dt.month, dt.day), dt.hour, dt.month, dt.minute) + __SECONDS_FROM_1970_TO_2000;
return unixTime;
}
I try with GCC and -O3 flag, here is the result:
PictureGodBolt