Arguably, get more useful values for __DATE__, __TIME__ & __FILE__ (linux version)

I know that __DATE__, __TIME__ & __FILE__ exist, but they are not MCU friendly, taking up too much space.
So I created an automated script that runs at compile time, and also grabs the Sketch name and folder. without the higher path taking away valuable memory space.
It requires a some minor changes to platform.txt (and also any EpoxyDuino make files) for maximum benefit; these are detailed in the generated file TimestampNow.h, which an example reads:

#pragma once
//# Generated via TimestampNow.sh in ~/git/MyArduinoStuff/MyUtes
//# For Arduino IDE, in ~/.arduino15/packages/arduino/hardware/avr/1.8.3/platform.txt,
//#  (# AVR compile patterns), add line ...
//   recipe.hooks.sketch.prebuild.1.pattern=/home/MyUser/git/MyArduinoStuff/libraries/MyUtes/TimestampNow.sh {build.source.path}
//#  (## Compile c files) + (## Compile c++ files), add fragment ...
//   -DPROJECT_NAME="{build.project_name}" # e.g. "MyProject.ino"
//# For EpoxyDuino, in Makefile add ...
//   TIMESTAMP_FORCE != ~/git/MyArduinoStuff/MyUtes/TimestampNow.sh
//# Inside .ino, maybe use SKETCH_HANDLE or PROJECT_HANDLE instead of __FILE__
//# Inside .ino, for compile time,  consider ...
//   Serial.println(F(TIMESTAMP_NOW_STR_CY_M_D_H_M_S_F)); // CCYY-mm-DD@HH:MM:SS.FFF  ; ideal if space not an issue
//# or
//   Serial.println(F(TIMESTAMP_NOW_STR_YMD "@" TIMESTAMP_NOW_STR_HM)); // YYmmDD@HHMM ; compromise if space limited
#define SKETCH_HANDLE "TestCharBuff3EditPhraseViaUDLR_Actions"  // Arduino IDE; {build.source.path}
#ifdef PROJECT_NAME // defined for ARDUINO IDE, not for EpoxyDuino
 #define PROJECT_HANDLE PROJECT_NAME // e.g. "MyProject.ino"
#else
 #define PROJECT_HANDLE SKETCH_HANDLE // e.g. "MyProject"
#endif
#define TIMESTAMP_NOW_STR_CY_M_D_H_M_S_F "2021-10-30@18:05:00.306"
#define TIMESTAMP_NOW_STR_CY_M_D_H_M_S "2021-10-30@18:05:00"
#define TIMESTAMP_NOW_STR_Y_M_D_H_M_S "21-10-30@18:05:00"
#define TIMESTAMP_NOW_STR_CY_M_D "2021-10-30"
#define TIMESTAMP_NOW_STR_Y_M_D "21-10-30"
#define TIMESTAMP_NOW_STR_H_M_S_F "18:05:00.306"
#define TIMESTAMP_NOW_STR_H_M_S "18:05:00"
#define TIMESTAMP_NOW_STR_YMD "211030"
#define TIMESTAMP_NOW_STR_HMS "180500"
#define TIMESTAMP_NOW_STR_HM "1805"

#define TIMESTAMP_NOW_NUM_CYMD_HMSF 20211030.180500306
#define TIMESTAMP_NOW_NUM_CYMD_HMS 20211030.180500
#define TIMESTAMP_NOW_NUM_YMD_HMS 211030.180500
#define TIMESTAMP_NOW_NUM_YMD_HM 211030.1805
#define TIMESTAMP_NOW_NUM_CYMD 20211030
#define TIMESTAMP_NOW_NUM_YMD 211030
#define TIMESTAMP_NOW_NUM_HMSF 18050030
#define TIMESTAMP_NOW_NUM_HMS 180500
#define TIMESTAMP_NOW_NUM_HM 1805

I suggest changing MyArduinoStuff, MyUtes , etc, to better match your environment.
The script to generate this is:

#!/bin/sh
if test -z "$1" # $1 is {build.source.path}; used by Arduino IDE run
then
  mySketchHandle=${PWD##*/} # not Arduino IDE; use last bit of PWD
  mySketchSource=" // Not Arduino IDE; maybe EpoxyDuino"
else
  mySketchHandle=$1 # Get {build.source.path}, passed as $1
  mySketchHandle=${mySketchHandle##*/} # Get last bit of {build.source.path}
  mySketchSource=" // Arduino IDE; {build.source.path}"
fi
cd ~/git/MyArduinoStuff/MyUtes # switch to Utilities folder
echo -n "building TimestampNow.h ... "
strDate=$(date +"%Y-%m-%d %H:%M:%S.%9N") # get date, to keep consistent
formatStrDate(){
  date $1 -d "$2"
}
echo -n " strDate=<$strDate> ... "
echo -n "" > TimestampNow.h

echo "#pragma once" >> TimestampNow.h
echo "//# Generated via TimestampNow.sh in ~/git/MyArduinoStuff/MyUtes" >> TimestampNow.h
echo "//# For Arduino IDE, in ~/.arduino15/packages/arduino/hardware/avr/1.8.3/platform.txt," >> TimestampNow.h
echo "//#  (# AVR compile patterns), add line ..." >> TimestampNow.h
echo "//   recipe.hooks.sketch.prebuild.1.pattern=/home/MyUser/git/MyArduinoStuff/libraries/MyUtes/TimestampNow.sh {build.source.path}" >> TimestampNow.h
echo "//#  (## Compile c files) + (## Compile c++ files), add fragment ..." >> TimestampNow.h
echo "//   -DPROJECT_NAME=\"{build.project_name}\" # e.g. \"MyProject.ino\"" >> TimestampNow.h
echo "//# For EpoxyDuino, in Makefile add ..." >> TimestampNow.h
echo "//   TIMESTAMP_FORCE != ~/git/MyArduinoStuff/MyUtes/TimestampNow.sh" >> TimestampNow.h
echo "//# Inside .ino, maybe use SKETCH_HANDLE or PROJECT_HANDLE instead of __FILE__" >> TimestampNow.h
echo "//# Inside .ino, for compile time,  consider ..." >> TimestampNow.h
echo "//   Serial.println(F(TIMESTAMP_NOW_STR_CY_M_D_H_M_S_F)); // CCYY-mm-DD@HH:MM:SS.FFF  ; ideal if space not an issue" >> TimestampNow.h
echo "//# or" >> TimestampNow.h
echo "//   Serial.println(F(TIMESTAMP_NOW_STR_YMD \"@\" TIMESTAMP_NOW_STR_HM)); // YYmmDD@HHMM ; compromise if space limited" >> TimestampNow.h

echo -n "#define SKETCH_HANDLE \"" >> TimestampNow.h
echo -n "$mySketchHandle" >> TimestampNow.h
echo "\" $mySketchSource" >> TimestampNow.h

echo "#ifdef PROJECT_NAME // defined for ARDUINO IDE, not for EpoxyDuino" >> TimestampNow.h
echo " #define PROJECT_HANDLE PROJECT_NAME // e.g. \"MyProject.ino\"" >> TimestampNow.h
echo "#else" >> TimestampNow.h
echo " #define PROJECT_HANDLE SKETCH_HANDLE // e.g. \"MyProject\"" >> TimestampNow.h
echo "#endif" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_CY_M_D_H_M_S_F " >> TimestampNow.h
formatStrDate "+\"%Y-%m-%d@%H:%M:%S.%3N\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_CY_M_D_H_M_S " >> TimestampNow.h
formatStrDate "+\"%Y-%m-%d@%H:%M:%S\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_Y_M_D_H_M_S " >> TimestampNow.h
formatStrDate "+\"%y-%m-%d@%H:%M:%S\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_CY_M_D " >> TimestampNow.h
formatStrDate "+\"%Y-%m-%d\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_Y_M_D " >> TimestampNow.h
formatStrDate "+\"%y-%m-%d\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_H_M_S_F " >> TimestampNow.h
formatStrDate "+\"%H:%M:%S.%3N\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_H_M_S " >> TimestampNow.h
formatStrDate "+\"%H:%M:%S\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_YMD " >> TimestampNow.h
formatStrDate "+\"%y%m%d\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_HMS " >> TimestampNow.h
formatStrDate "+\"%H%M%S\"" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_STR_HM " >> TimestampNow.h
formatStrDate "+\"%H%M\"" "$strDate" >> TimestampNow.h

echo "" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_CYMD_HMSF " >> TimestampNow.h
formatStrDate "+%Y%m%d.%H%M%S%3N" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_CYMD_HMS " >> TimestampNow.h
formatStrDate "+%Y%m%d.%H%M%S" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_YMD_HMS " >> TimestampNow.h
formatStrDate "+%y%m%d.%H%M%S" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_YMD_HM " >> TimestampNow.h
formatStrDate "+%y%m%d.%H%M" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_CYMD " >> TimestampNow.h
formatStrDate "+%Y%m%d" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_YMD " >> TimestampNow.h
formatStrDate "+%y%m%d" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_HMSF " >> TimestampNow.h
formatStrDate "+%H%M%S%2N" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_HMS " >> TimestampNow.h
formatStrDate "+%H%M%S" "$strDate" >> TimestampNow.h

echo -n "#define TIMESTAMP_NOW_NUM_HM " >> TimestampNow.h
formatStrDate "+%H%M" "$strDate" >> TimestampNow.h

echo "" >> TimestampNow.h
echo " ... done."

These are resolved by the pre-processor. Can you somehow quantity the space savings your solution brings?

I like self-documenting programmes. I pick up a AVR chip and think "What's on it? When was it compiled?" and plug it in to see. Some have less than 2K; Flash space is important to me. I think it's obvious which takes up less space, and still provides useful information
Serial.println(F("/home/XXXXX/git/XXXXXXXXXXX/AUnit_Tests_Folder/XXXXXXXXUtes_Test_Folder/TestCharBuff3EditPhraseViaUDLR_Actions/TestCharBuff3EditPhraseViaUDLR_Actions.ino "))
or
Serial.println(F("TestCharBuff3EditPhraseViaUDLR_Actions"))
Which is more compact? And easier to convert to a real date/time object?
F("Oct 30 2021@18:05:00")
or
F("211030@1805") or 211030.1805
? Maybe it's not obvious which is more compact to others, but I have been ecstatic at times to save a few dozen bytes.

Could you please put a number on too much space claim?

OK. Thanks. If you need that degree of flexibility, then integrating a script call into the IDE to generate preprocessor macros is a good solution. It doesn't match the way I work because I use only __DATE__, __TIME__ and my own program name with version number, which I generate by hand, and write it all out at the beginning of the sketch, so I would not be using it. But the idea could otherwise be interesting.

My current sketch has __FILE__ that is 153+1 bytes; using SKETCH_HANDLE uses 39+1 bytes, saving 114 bytes.
Using __DATE__ + __TIME__ uses 19+2 bytes; using TIMESTAMP_NOW_STR_YMD TIMESTAMP_NOW_STR_HM uses 10+1 bytes, using TIMESTAMP_NOW_NUM_YMD_HM as a float uses 4 bytes and TIMESTAMP_NOW_NUM_CYMD_HMSF as a true (none-AVR) double uses 8 bytes, saving from 10 to 17 bytes.
So a basic 'name and date-time' storage could reduce Flash usage from 175 down to 44 bytes.

So about 0.4% on Uno. I don’t think this qualifies as too much

Can you please put a number for the ATTiny processors? Thanks.

You didn’t say anything in your OP about that you are targeting ATTiny. Uno is the most popular Arduino board so I feel it is fair to compare your savings for this board. Other boards have much more memory, shall we compare the saving on them too to be thorough?

What is the actual utility of either method? If it's for setting an RTC, there are better ways. What is the practical use of a program that you have to reload every time you change the RTC battery? If there is no RTC, it is only useful as a demo, as the time will be lost on power down.

It's geared for anyone wanting to save memory. On reflection, I'm not sure that a percentage saving makes much sense; programmes either fit in memory or not, and then it's not often a matter of saving memory by percentage but as and where we can. I once had a Nano programme that was 20-odd bytes too big. That's all I needed to save; a tiny fraction of a percent.
But thanks for the offer anyway.

I'm trying to work out why some people with such limited outlooks are bothering to comment on my post.
When you have a chip installed in a system, and Something Unexpected happens, how do you know what's in the chip? In my 45+ years of programme development, a common problem is determining what version of which programme is involved.
My typical sketch will start off displaying stuff like:

2021-10-30@18:05:00.306, ARDUINO=10815 RAMEND=0x8FF FLASHEND=0x7FFF F_CPU=16000000L.
TestCharBuff3EditPhraseViaUDLR_Actions
LED_BUILTIN=13
F_CPU=16000000 (16.00MHz)

This gives me a whole lot of information about the chip without much effort. It's nothing to do with RTC (although I have done those). It's to let me know which version of the code has been installed - its project file and date/time.

For me, knowing the date and time of compilation would not be very useful. It would send me searching around my various projects and looking at dates, which would not be an easy task. What I do, is self-manage version numbers. For applications that make the serial port human readable, I print a boot message that contains the version number and identity of the program. That steers me quickly to the source code, because the program names also embed the version number. I also self-manage the memory allocation and hardware assignments, the former varies because I use multiple platforms, the latter is prominently visible in the source file. I keep all those in sections or header files to facilitate porting it to different platforms.

Here is an example:

Welcome, connected to LED device RGBSetDemoSerial_12

1 Like

I guess we work in different ways. I use git, and have 22 (just checked) saved versions of my latest programme in the last 7 days. Manually updating version numbers is too much hassle and prone to mistakes. Yes, I can create tags and branches, but pinning a program to a definite project and point in time works better for me.

How many versions in a day? Do you really need to store the time?

Also it is only on a Harvard architecture machine that the string constant generated by macros like ' __TIMESTAMP__ are not stored in flash, which MCU's usually have more of, than RAM.

Since you are using Git, why not use a short hash instead of a timestamp?

4 to 5 would be a typical day. I regularly commit my changes to try to limit any rework to just a few hours When Things Go Wrong.

Only if I want to know which version of the source it is. Which is always.
I also want to know which version of hardware it's for, which version of compiler it is, and anything else that can vary.

A) Your last sentence is completely wrong (except about more Flash being available than RAM). i) The architecture is irrelevant. ii) Harvard architecture (like Arduino) DOES store string constants in Flash. Same with Von-Neumann.
B) No string constants are ever stored in RAM when the programme is initially loaded (i,e. before the loader might shift from non-volatile into RAM, which is often a waste of RAM space). All string constants are initially stored in non-volatile memory; whether they then get moved from there to RAM depends on how the constant is defined. To reduce RAM usage, I use a mixture of __FlashStringHelper* (F()) and const PROGMEM char* depending on whether it's inside or outside functions. Remember, that constant strings will ALWAYS take up non-volatile space regardless of architecture.
C) The Arduino IDE knows exactly how much Flash is used; When it runs out, it's run out and knows at compile (OK, link) time. RAM usage is a bit of a guess, of 'permanent' (i.e. non-stack) usage; it's actually more than just 'Global' (if it isn't, then that's a flaw in the compiler/linker; it should take static-in-function into account, which does not have Global visibility).

A) I haven't worked out how to automatically get the git hash into my source code.
B) It also would require a look-up process to decide whether 1e3134d is before or after da09b17. Timestamps do that de facto by using ISO8601-type sequencing which ensures a simple comparison tells me so - something __DATE__ doesn't do, with its crazy MonthByName-Day-Year ordering.

Of course, all constants must somehow originate in flash since that's the only non volatile storage. What I meant, with the Harvard architecture it is mandatory that the constant data be transferred to RAM first before it can be accessed as a normal variable. On a Von Neumann machine, constant data can be directly accessed so the compiler just places it there and generates reference addresses for it.

The remainder of my comments tried to address your reason for avoiding constant strings, I assumed that it was because on a Harvard machine, the "lazy" way to implement a 'const' is to allocate RAM for it (vs. moving it one byte at a time), populate it from flash at boot time, and prohibit write access to it by means of data type enforcement. I'm not sure, but I suspect that is how things are done in AVR-GCC. That would impact the run time RAM size, so I assumed that was the root of your objective to reduce string size.

Often, assumptions are wrong. Oh, well...

Again, usually there is much more flash than RAM, not just because programmers use more, but because of economics - RAM cells use much more die area than flash cells.

This command will give you the short hash of the ref currently checked out in a repository:

git log --no-show-signature -n 1 --format=%h

That's just the sort of thing Git was made for.

Since you can have any revision checked out at any time, including revisions that aren't even in the primary branch, the time of the compilation is not guaranteed to correlate to the revision of the software being compiled.